http实现源码(40-1)
2013-11-08 10:56
323 查看
HttpRequest头文件(包含实现)
HttpResquest.h// Copyright 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file. // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. #ifndef MUDUO_NET_HTTP_HTTPREQUEST_H #define MUDUO_NET_HTTP_HTTPREQUEST_H #include <muduo/base/copyable.h> #include <muduo/base/Timestamp.h> #include <muduo/base/Types.h> #include <map> #include <assert.h> #include <stdio.h> namespace muduo { namespace net { class HttpRequest : public muduo::copyable { public: enum Method { kInvalid, kGet, kPost, kHead, kPut, kDelete }; enum Version { kUnknown, kHttp10, kHttp11 }; HttpRequest() : method_(kInvalid), version_(kUnknown) { } void setVersion(Version v) { version_ = v; } Version getVersion() const { return version_; } /*设置请求方法*/ bool setMethod(const char* start, const char* end) { assert(method_ == kInvalid); string m(start, end); if (m == "GET") { method_ = kGet; } else if (m == "POST") { method_ = kPost; } else if (m == "HEAD") { method_ = kHead; } else if (m == "PUT") { method_ = kPut; } else if (m == "DELETE") { method_ = kDelete; } else { method_ = kInvalid; } return method_ != kInvalid; } /*返回请求方法*/ Method method() const { return method_; } /*请求方法转为字符串*/ const char* methodString() const { const char* result = "UNKNOWN"; switch(method_) { case kGet: result = "GET"; break; case kPost: result = "POST"; break; case kHead: result = "HEAD"; break; case kPut: result = "PUT"; break; case kDelete: result = "DELETE"; break; default: break; } return result; } /*设置请求路径*/ void setPath(const char* start, const char* end) { path_.assign(start, end); } /*返回请求路径*/ const string& path() const { return path_; } /*设置接收时间*/ void setReceiveTime(Timestamp t) { receiveTime_ = t; } Timestamp receiveTime() const { return receiveTime_; } /*添加一个头部信息*/ /* Accept-Language(start):(colon) zh-CN(end) -->Accept-Language zh-CN */ void addHeader(const char* start, const char* colon, const char* end) { string field(start, colon); // header域 ++colon; // 去除左空格 while (colon < end && isspace(*colon)) { ++colon; } string value(colon, end); // header值 // 去除右空格 while (!value.empty() && isspace(value[value.size()-1])) { value.resize(value.size()-1); } headers_[field] = value; } /*根据头域,获得头域的信息*/ string getHeader(const string& field) const { string result; std::map<string, string>::const_iterator it = headers_.find(field); if (it != headers_.end()) { result = it->second; } return result; } const std::map<string, string>& headers() const { return headers_; } void swap(HttpRequest& that) { /*貌似少了version的交换*/ std::swap(method_, that.method_); path_.swap(that.path_); receiveTime_.swap(that.receiveTime_); headers_.swap(that.headers_); } private: Method method_; // 请求方法 Version version_; // 协议版本1.0/1.1 string path_; // 请求路径 Timestamp receiveTime_; // 请求时间 std::map<string, string> headers_; // header列表 }; } } #endif // MUDUO_NET_HTTP_HTTPREQUEST_H
HttpResponse头文件
HttpResponse.h// Copyright 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file. // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. #ifndef MUDUO_NET_HTTP_HTTPRESPONSE_H #define MUDUO_NET_HTTP_HTTPRESPONSE_H #include <muduo/base/copyable.h> #include <muduo/base/Types.h> #include <map> namespace muduo { namespace net { class Buffer; class HttpResponse : public muduo::copyable { public: enum HttpStatusCode { kUnknown, k200Ok = 200, // 成功 k301MovedPermanently = 301, // 301重定向,请求的页面永久性移至另一个地址 k400BadRequest = 400, // 错误的请求,语法格式有错,服务器无法处理此请求 k404NotFound = 404, // 请求的网页不存在 }; explicit HttpResponse(bool close) : statusCode_(kUnknown), closeConnection_(close) { } void setStatusCode(HttpStatusCode code) { statusCode_ = code; } void setStatusMessage(const string& message) { statusMessage_ = message; } void setCloseConnection(bool on) { closeConnection_ = on; } bool closeConnection() const { return closeConnection_; } // 设置文档媒体类型(MIME) void setContentType(const string& contentType) { addHeader("Content-Type", contentType); } // FIXME: replace string with StringPiece void addHeader(const string& key, const string& value) { headers_[key] = value; } void setBody(const string& body) { body_ = body; } void appendToBuffer(Buffer* output) const; // 将HttpResponse添加到Buffer private: std::map<string, string> headers_; // header列表 HttpStatusCode statusCode_; // 状态响应码 // FIXME: add http version string statusMessage_; // 状态响应码对应的文本信息 bool closeConnection_; // 是否关闭连接 string body_; // 实体 }; } } #endif // MUDUO_NET_HTTP_HTTPRESPONSE_H
HttpResponse源文件
HttpResponse.cc// Copyright 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file. // Author: Shuo Chen (chenshuo at chenshuo dot com) // #include <muduo/net/http/HttpResponse.h> #include <muduo/net/Buffer.h> #include <stdio.h> using namespace muduo; using namespace muduo::net; void HttpResponse::appendToBuffer(Buffer* output) const { char buf[32]; // 添加响应头 snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_); output->append(buf); output->append(statusMessage_); output->append("\r\n"); if (closeConnection_) { // 如果是短连接,不需要告诉浏览器Content-Length,浏览器也能正确处理 // 短链接不会出现粘包问题 output->append("Connection: close\r\n"); } else { snprintf(buf, sizeof buf, "Content-Length: %zd\r\n", body_.size()); // 实体长度 output->append(buf); output->append("Connection: Keep-Alive\r\n"); } // header列表 for (std::map<string, string>::const_iterator it = headers_.begin(); it != headers_.end(); ++it) { output->append(it->first); output->append(": "); output->append(it->second); output->append("\r\n"); } output->append("\r\n"); // header与body之间的空行 output->append(body_); }
HttpContext文件
HttpContext.h// Copyright 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file. // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this. #ifndef MUDUO_NET_HTTP_HTTPCONTEXT_H #define MUDUO_NET_HTTP_HTTPCONTEXT_H #include <muduo/base/copyable.h> #include <muduo/net/http/HttpRequest.h> namespace muduo { namespace net { class HttpContext : public muduo::copyable { public: enum HttpRequestParseState { kExpectRequestLine,//正处于请求行的状态 kExpectHeaders, //正处于请求头的状态 kExpectBody, //正处于请求实体的状态 kGotAll, //全部都解析完毕 }; HttpContext() : state_(kExpectRequestLine) { } // default copy-ctor, dtor and assignment are fine bool expectRequestLine() const { return state_ == kExpectRequestLine; } bool expectHeaders() const { return state_ == kExpectHeaders; } bool expectBody() const { return state_ == kExpectBody; } bool gotAll() const { return state_ == kGotAll; } void receiveRequestLine() { state_ = kExpectHeaders; } /*注意这里没有处理body实体的请求*/ void receiveHeaders() { state_ = kGotAll; } // FIXME // 重置HttpContext状态 void reset() { state_ = kExpectRequestLine; HttpRequest dummy; request_.swap(dummy); } const HttpRequest& request() const { return request_; } HttpRequest& request() { return request_; } private: HttpRequestParseState state_; // 请求解析状态 HttpRequest request_; // http请求 }; } } #endif // MUDUO_NET_HTTP_HTTPCONTEXT_H
HttpServer头文件
HttpServer.h// Copyright 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file. // Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is a public header file, it must only include public header files. #ifndef MUDUO_NET_HTTP_HTTPSERVER_H #define MUDUO_NET_HTTP_HTTPSERVER_H #include <muduo/net/TcpServer.h> #include <boost/noncopyable.hpp> namespace muduo { namespace net { class HttpRequest; class HttpResponse; /// A simple embeddable HTTP server designed for report status of a program. /// It is not a fully HTTP 1.1 compliant server, but provides minimum features /// that can communicate with HttpClient and Web browser. /// It is synchronous, just like Java Servlet. class HttpServer : boost::noncopyable { public: typedef boost::function<void (const HttpRequest&, HttpResponse*)> HttpCallback; HttpServer(EventLoop* loop, const InetAddress& listenAddr, const string& name); ~HttpServer(); // force out-line dtor, for scoped_ptr members. /// Not thread safe, callback be registered before calling start(). void setHttpCallback(const HttpCallback& cb) { httpCallback_ = cb; } /*subIO thread numbers*/ void setThreadNum(int numThreads) { server_.setThreadNum(numThreads); } void start(); private: void onConnection(const TcpConnectionPtr& conn); /*当以http请求到来时 onMessage--->onRequest--->HttpCallback */ void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime); void onRequest(const TcpConnectionPtr&, const HttpRequest&); TcpServer server_; HttpCallback httpCallback_; // 在处理http请求(即调用onRequest)的过程中回调此函数,对请求进行具体的处理 }; } } #endif // MUDUO_NET_HTTP_HTTPSERVER_H
HttpServer源文件
HttpServer.cc// Copyright 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file. // Author: Shuo Chen (chenshuo at chenshuo dot com) // #include <muduo/net/http/HttpServer.h> #include <muduo/base/Logging.h> #include <muduo/net/http/HttpContext.h> #include <muduo/net/http/HttpRequest.h> #include <muduo/net/http/HttpResponse.h> #include <boost/bind.hpp> using namespace muduo; using namespace muduo::net; /* GET / HTTP/1.1 (请求行) Accept: image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword(请求头) Accept-Language: zh-CN(请求头) User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Tablet PC 2.0)(请求头) Accept-Encoding: gzip, deflate(请求头) Host: 192.168.159.188:800(请求头) Connection: Keep-Alive(请求头) */ namespace muduo { namespace net { namespace detail { // FIXME: move to HttpContext class bool processRequestLine(const char* begin, const char* end, HttpContext* context) { bool succeed = false; const char* start = begin; const char* space = std::find(start, end, ' '); HttpRequest& request = context->request(); if (space != end && request.setMethod(start, space)) // 解析请求方法 { start = space+1; space = std::find(start, end, ' '); if (space != end) { request.setPath(start, space); // 解析PATH start = space+1; succeed = end-start == 8 && std::equal(start, end-1, "HTTP/1."); if (succeed) { if (*(end-1) == '1') { request.setVersion(HttpRequest::kHttp11); // HTTP/1.1 } else if (*(end-1) == '0') { request.setVersion(HttpRequest::kHttp10); // HTTP/1.0 } else { succeed = false; } } } } return succeed; } // FIXME: move to HttpContext class // return false if any error // 开始解析请求 bool parseRequest(Buffer* buf, HttpContext* context, Timestamp receiveTime) { bool ok = true; bool hasMore = true; while (hasMore) { if (context->expectRequestLine()) // 处于解析请求行状态 { const char* crlf = buf->findCRLF(); if (crlf) { ok = processRequestLine(buf->peek(), crlf, context); // 解析请求行 ,*crlf ='\r' if (ok) { context->request().setReceiveTime(receiveTime); // 设置请求时间 buf->retrieveUntil(crlf + 2); // 将请求行从buf中取回,包括\r\n context->receiveRequestLine(); // 将HttpContext状态改为kExpectHeaders } else { hasMore = false; } } else { hasMore = false; } } else if (context->expectHeaders()) // 解析header { const char* crlf = buf->findCRLF(); if (crlf) { const char* colon = std::find(buf->peek(), crlf, ':'); //冒号所在位置 if (colon != crlf) { context->request().addHeader(buf->peek(), colon, crlf); } else { // empty line, end of header context->receiveHeaders(); // HttpContext将状态改为kGotAll hasMore = !context->gotAll(); } buf->retrieveUntil(crlf + 2); // 将header从buf中取回,包括\r\n } else { hasMore = false; } } else if (context->expectBody()) // 当前还不支持请求中带body { // FIXME: } } return ok; } void defaultHttpCallback(const HttpRequest&, HttpResponse* resp) { resp->setStatusCode(HttpResponse::k404NotFound); resp->setStatusMessage("Not Found"); resp->setCloseConnection(true); } } } } HttpServer::HttpServer(EventLoop* loop, const InetAddress& listenAddr, const string& name) : server_(loop, listenAddr, name), httpCallback_(detail::defaultHttpCallback) { server_.setConnectionCallback( boost::bind(&HttpServer::onConnection, this, _1)); server_.setMessageCallback( boost::bind(&HttpServer::onMessage, this, _1, _2, _3)); } HttpServer::~HttpServer() { } void HttpServer::start() { LOG_WARN << "HttpServer[" << server_.name() << "] starts listenning on " << server_.hostport(); server_.start(); } void HttpServer::onConnection(const TcpConnectionPtr& conn) { if (conn->connected()) { //boost any conn->setContext(HttpContext()); // TcpConnection与一个HttpContext绑定 } } void HttpServer::onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime) { HttpContext* context = boost::any_cast<HttpContext>(conn->getMutableContext()); if (!detail::parseRequest(buf, context, receiveTime)) { conn->send("HTTP/1.1 400 Bad Request\r\n\r\n"); conn->shutdown(); } // 请求消息解析完毕 if (context->gotAll()) { onRequest(conn, context->request()); context->reset(); // 本次请求处理完毕,重置HttpContext,适用于长连接 } } void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req) { const string& connection = req.getHeader("Connection"); //是否关闭连接 bool close = connection == "close" || (req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive"); HttpResponse response(close); httpCallback_(req, &response);//回调用户函数 Buffer buf; response.appendToBuffer(&buf); conn->send(&buf); if (response.closeConnection()) { conn->shutdown(); } }
测试程序
#include <muduo/net/http/HttpServer.h> #include <muduo/net/http/HttpRequest.h> #include <muduo/net/http/HttpResponse.h> #include <muduo/net/EventLoop.h> #include <muduo/base/Logging.h> #include <iostream> #include <map> using namespace muduo; using namespace muduo::net; extern char favicon[555]; bool benchmark = false; // 实际的请求处理 void onRequest(const HttpRequest& req, HttpResponse* resp) { std::cout << "Headers " << req.methodString() << " " << req.path() << std::endl; if (!benchmark) { const std::map<string, string>& headers = req.headers(); for (std::map<string, string>::const_iterator it = headers.begin(); it != headers.end(); ++it) { std::cout << it->first << ": " << it->second << std::endl; } } if (req.path() == "/") { resp->setStatusCode(HttpResponse::k200Ok); resp->setStatusMessage("OK"); resp->setContentType("text/html"); resp->addHeader("Server", "Muduo"); string now = Timestamp::now().toFormattedString(); resp->setBody("<html><head><title>This is title</title></head>" "<body><h1>Hello</h1>Now is " + now + "</body></html>"); } else if (req.path() == "/favicon.ico") { resp->setStatusCode(HttpResponse::k200Ok); resp->setStatusMessage("OK"); resp->setContentType("image/png"); resp->setBody(string(favicon, sizeof favicon)); } else if (req.path() == "/hello") { resp->setStatusCode(HttpResponse::k200Ok); resp->setStatusMessage("OK"); resp->setContentType("text/plain"); resp->addHeader("Server", "Muduo"); resp->setBody("hello, world!\n"); } else { resp->setStatusCode(HttpResponse::k404NotFound); resp->setStatusMessage("Not Found"); resp->setCloseConnection(true); } } int main(int argc, char* argv[]) { int numThreads = 0; if (argc > 1) { benchmark = true; Logger::setLogLevel(Logger::WARN); numThreads = atoi(argv[1]); } EventLoop loop; HttpServer server(&loop, InetAddress(8000), "dummy"); server.setHttpCallback(onRequest); server.setThreadNum(numThreads); server.start(); loop.loop(); } // 这是一个图片数据 char favicon[555] = { '\x89', 'P', 'N', 'G', '\xD', '\xA', '\x1A', '\xA', '\x0', '\x0', '\x0', '\xD', 'I', 'H', 'D', 'R', '\x0', '\x0', '\x0', '\x10', '\x0', '\x0', '\x0', '\x10', '\x8', '\x6', '\x0', '\x0', '\x0', '\x1F', '\xF3', '\xFF', 'a', '\x0', '\x0', '\x0', '\x19', 't', 'E', 'X', 't', 'S', 'o', 'f', 't', 'w', 'a', 'r', 'e', '\x0', 'A', 'd', 'o', 'b', 'e', '\x20', 'I', 'm', 'a', 'g', 'e', 'R', 'e', 'a', 'd', 'y', 'q', '\xC9', 'e', '\x3C', '\x0', '\x0', '\x1', '\xCD', 'I', 'D', 'A', 'T', 'x', '\xDA', '\x94', '\x93', '9', 'H', '\x3', 'A', '\x14', '\x86', '\xFF', '\x5D', 'b', '\xA7', '\x4', 'R', '\xC4', 'm', '\x22', '\x1E', '\xA0', 'F', '\x24', '\x8', '\x16', '\x16', 'v', '\xA', '6', '\xBA', 'J', '\x9A', '\x80', '\x8', 'A', '\xB4', 'q', '\x85', 'X', '\x89', 'G', '\xB0', 'I', '\xA9', 'Q', '\x24', '\xCD', '\xA6', '\x8', '\xA4', 'H', 'c', '\x91', 'B', '\xB', '\xAF', 'V', '\xC1', 'F', '\xB4', '\x15', '\xCF', '\x22', 'X', '\x98', '\xB', 'T', 'H', '\x8A', 'd', '\x93', '\x8D', '\xFB', 'F', 'g', '\xC9', '\x1A', '\x14', '\x7D', '\xF0', 'f', 'v', 'f', '\xDF', '\x7C', '\xEF', '\xE7', 'g', 'F', '\xA8', '\xD5', 'j', 'H', '\x24', '\x12', '\x2A', '\x0', '\x5', '\xBF', 'G', '\xD4', '\xEF', '\xF7', '\x2F', '6', '\xEC', '\x12', '\x20', '\x1E', '\x8F', '\xD7', '\xAA', '\xD5', '\xEA', '\xAF', 'I', '5', 'F', '\xAA', 'T', '\x5F', '\x9F', '\x22', 'A', '\x2A', '\x95', '\xA', '\x83', '\xE5', 'r', '9', 'd', '\xB3', 'Y', '\x96', '\x99', 'L', '\x6', '\xE9', 't', '\x9A', '\x25', '\x85', '\x2C', '\xCB', 'T', '\xA7', '\xC4', 'b', '1', '\xB5', '\x5E', '\x0', '\x3', 'h', '\x9A', '\xC6', '\x16', '\x82', '\x20', 'X', 'R', '\x14', 'E', '6', 'S', '\x94', '\xCB', 'e', 'x', '\xBD', '\x5E', '\xAA', 'U', 'T', '\x23', 'L', '\xC0', '\xE0', '\xE2', '\xC1', '\x8F', '\x0', '\x9E', '\xBC', '\x9', 'A', '\x7C', '\x3E', '\x1F', '\x83', 'D', '\x22', '\x11', '\xD5', 'T', '\x40', '\x3F', '8', '\x80', 'w', '\xE5', '3', '\x7', '\xB8', '\x5C', '\x2E', 'H', '\x92', '\x4', '\x87', '\xC3', '\x81', '\x40', '\x20', '\x40', 'g', '\x98', '\xE9', '6', '\x1A', '\xA6', 'g', '\x15', '\x4', '\xE3', '\xD7', '\xC8', '\xBD', '\x15', '\xE1', 'i', '\xB7', 'C', '\xAB', '\xEA', 'x', '\x2F', 'j', 'X', '\x92', '\xBB', '\x18', '\x20', '\x9F', '\xCF', '3', '\xC3', '\xB8', '\xE9', 'N', '\xA7', '\xD3', 'l', 'J', '\x0', 'i', '6', '\x7C', '\x8E', '\xE1', '\xFE', 'V', '\x84', '\xE7', '\x3C', '\x9F', 'r', '\x2B', '\x3A', 'B', '\x7B', '7', 'f', 'w', '\xAE', '\x8E', '\xE', '\xF3', '\xBD', 'R', '\xA9', 'd', '\x2', 'B', '\xAF', '\x85', '2', 'f', 'F', '\xBA', '\xC', '\xD9', '\x9F', '\x1D', '\x9A', 'l', '\x22', '\xE6', '\xC7', '\x3A', '\x2C', '\x80', '\xEF', '\xC1', '\x15', '\x90', '\x7', '\x93', '\xA2', '\x28', '\xA0', 'S', 'j', '\xB1', '\xB8', '\xDF', '\x29', '5', 'C', '\xE', '\x3F', 'X', '\xFC', '\x98', '\xDA', 'y', 'j', 'P', '\x40', '\x0', '\x87', '\xAE', '\x1B', '\x17', 'B', '\xB4', '\x3A', '\x3F', '\xBE', 'y', '\xC7', '\xA', '\x26', '\xB6', '\xEE', '\xD9', '\x9A', '\x60', '\x14', '\x93', '\xDB', '\x8F', '\xD', '\xA', '\x2E', '\xE9', '\x23', '\x95', '\x29', 'X', '\x0', '\x27', '\xEB', 'n', 'V', 'p', '\xBC', '\xD6', '\xCB', '\xD6', 'G', '\xAB', '\x3D', 'l', '\x7D', '\xB8', '\xD2', '\xDD', '\xA0', '\x60', '\x83', '\xBA', '\xEF', '\x5F', '\xA4', '\xEA', '\xCC', '\x2', 'N', '\xAE', '\x5E', 'p', '\x1A', '\xEC', '\xB3', '\x40', '9', '\xAC', '\xFE', '\xF2', '\x91', '\x89', 'g', '\x91', '\x85', '\x21', '\xA8', '\x87', '\xB7', 'X', '\x7E', '\x7E', '\x85', '\xBB', '\xCD', 'N', 'N', 'b', 't', '\x40', '\xFA', '\x93', '\x89', '\xEC', '\x1E', '\xEC', '\x86', '\x2', 'H', '\x26', '\x93', '\xD0', 'u', '\x1D', '\x7F', '\x9', '2', '\x95', '\xBF', '\x1F', '\xDB', '\xD7', 'c', '\x8A', '\x1A', '\xF7', '\x5C', '\xC1', '\xFF', '\x22', 'J', '\xC3', '\x87', '\x0', '\x3', '\x0', 'K', '\xBB', '\xF8', '\xD6', '\x2A', 'v', '\x98', 'I', '\x0', '\x0', '\x0', '\x0', 'I', 'E', 'N', 'D', '\xAE', 'B', '\x60', '\x82', };
相关文章推荐
- HTTP代理实现请求报文的拦截与篡改9--实现篡改功能后的演示+源码下载
- 看C#实现源码,可以参考算法 HttpUtility.UrlEncode
- 一个下载SVN源码+http协议的java实现
- 深入剖析Spring Web源码(五) - DispatcherServlet的实现 - 通用Servlet和HTTP Servlet
- Android中实现多行、水平滚动的分页的Gridview实例源码 详细出处参考:http://www.jb51.net/article/38169.htm
- HTTP代理实现请求报文的拦截与篡改2--功能介绍+源码下载
- Android 4.4以上使用HttpURLConnection底层使用OkHttp实现的源码分析
- asp.net+VML+XMLHTTP实现无刷新动态曲线图(附源码)
- Apache HTTP Server 2.4版本的源码安装配置及实现
- Apache HttpAsyncClient源码解读 (如何实现异步IO)
- epoll_create函数实现源码分析 http://blog.csdn.net/lmh12506/article/details/7556188
- 【源码剖析】tinyhttpd —— C 语言实现最简单的 HTTP 服务器
- node http fs 实现 抓取网页源码并保存
- nginx源码分析之http解码实现
- okhttp源码解析-http协议的实现-重定向
- HTTP严格安全传输(HTTP Strict Transport Security, HSTS)chromuim实现源码分析(一)
- 【源码剖析】tinyhttpd —— C 语言实现最简单的 HTTP 服务器
- OKHttp源码分析3 - HttpEngine底层实现
- Android中原http请求的https实现(URLConnection 、volley)(volley不修改源码)
- tio-http-server 源码浅析(一)HttpRequestDecoder的实现