接下來,我們將著重介紹一下Dispatcher,因為這個類才是實現的關鍵
下面這個方法完成轉寄,參數是我們之前建立的HttpRequest
首先,我們根據指定的host和port建立了一個Socket,該Socket串連到真正的主機
然後,我們調用了request方法,這個方法將request轉寄出去,比較簡單,僅僅是將要求標頭寫到Socket的OutputStream裡面。
第三步,我們使用HttpResponseFactory的read方法,從Socket的InputStream裡面讀取並封裝出一個HttpResponse對象。
第四步,將回應標頭和響應流都寫到用戶端。用戶端的OutputStream從HttpRequest對象裡面可以得到。
/** * @param request - void */ public void dispatch(HttpRequest request, HttpResponse response, ProxyHost proxyHost) { String host = proxyHost.getHost(); int port = proxyHost.getPort(); Socket socket = null; try { socket = this.createSocket(host, port); socket.setSoTimeout(10000); socket.setKeepAlive(false); InputStream socketInputStream = socket.getInputStream(); OutputStream socketOutputStream = socket.getOutputStream(); if(logger.isDebugEnabled()) { // logger.debug("------------------ request.header\r\n" + request.toString()); } this.request(request, socketOutputStream); HttpResponse httpResponse = HttpConnectionFactory.createHttpResponse(socketInputStream, socketOutputStream); if(httpResponse != null) { response.setHttpHeader(httpResponse.getHttpHeader().clone()); response.setChunked(httpResponse.getChunked()); response.setContentType(httpResponse.getContentType()); response.setStatus(httpResponse.getStatus()); response.setReasonPhrase(httpResponse.getReasonPhrase()); this.resonse(request, httpResponse, request.getOutputStream()); response.setContentLength(httpResponse.getContentLength()); } } catch(IOException e) { if(logger.isErrorEnabled()) { logger.error(request.getRequestURL(), e); } } finally { if(socket != null) { try { socket.close(); } catch(IOException e) { } } } }
這裡是request方法:
1. 首先我們需要對Http的要求標頭進行修改,主要是修改請求主機和連接埠號碼,否則伺服器會認為請求的不是自己,因為客戶機發的請求是到我們的代理程式的請求,而實際上我們僅僅是做個代理,所以我們需要修改一下它,然後把它發給真正的主機
2. 將要求標頭發給服務期,僅僅是將要求標頭字串寫到OutputStream裡面罷了。
3. 將客戶機的其他請求資料發給伺服器,例如POST請求或者上傳檔案的話。但是不同的請求發送的資料是不一樣的,所以我們的程式必須能夠知道客戶機發送了多少資料,我們使用ContentPump.pumpContentStream()這個方法將請求資料發到伺服器,它像是一個抽水機,把一個管道裡面的資料抽到另外一個管道裡面。但是它必須事Crowdsourced Security Testing道要抽多少,否則,阻塞IO在資料讀取到最後的時候,會被阻塞。
/** * @param request * @param outputStream * @throws IOException */ private void request(HttpRequest request, OutputStream outputStream) throws IOException { String host = InetAddress.getLocalHost().getHostAddress(); if(useXForwardedFor) { String xForwardedFor = request.getHeader("X-Forwarded-For"); if(xForwardedFor == null) { xForwardedFor = host; } else { xForwardedFor = "," + host; } // local: not set http_client_ip request.setHeader("HTTP_CLIENT_IP", request.getRemoteAddr()); request.setHeader("X-Forwarded-For", xForwardedFor); } String headers = request.toString(); outputStream.write(headers.getBytes()); outputStream.flush(); HttpStream.pipe(request.getInputStream(), outputStream, request.getContentLength()); }