zoukankan      html  css  js  c++  java
  • HTTP代理实现请求报文的拦截与篡改7将接收到的响应报文返回给客户端

    返回目录  

      将从服务器端接收的响应报文返回给客户端    

      OKAY,到此,从服务端接收响应报文,算是全部讲完了,那么下一步,自然就是大结局:将从服务端接收到的响应报文包装后再发给客户端了。万里长征终于快到头了,东方姑娘也快要掏心救人了, 是不是有点小兴奋,当然兴奋归兴奋,最后这几里路还是要坚持走完的 。

     

    this.ObtainRequest()   // 获取请求信息 
    this.Response.ResendRequest() // 将请求报文重新包装后转发给目标服务器      
    this.Response.ReadResponse() // 读取从目标服务器返回的信息 
    this.ReturnResponse() // 将从目标服务器读取的信息返回给客户端  

      Session类Execute方法的四大神器,前面三个已经搞定了,只剩下这最后一个 this.ReturnResponse()了。

      既然是this。这个ReturnResponse自然在Session类里了   。   

      下面先一窥面目。 

     1 internal bool ReturnResponse()
     2 {
     3   bool flag = false;
     4   this.Timers.ClientBeginResponse = this.Timers.ClientDoneResponse = DateTime.Now;
     5   try
     6   {
     7     if ((this.Request.ClientPipe != null) && this.Request.ClientPipe.Connected)
     8     {
     9       this.Request.ClientPipe.Send(this.Response.Headers.ToByteArray(true, true));
    10       this.Request.ClientPipe.Send(this.ResponseBodyBytes);
    11       this.Timers.ClientDoneResponse = DateTime.Now;
    12       this.Request.ClientPipe.End();
    13       flag = true;
    14     }
    15     else
    16     {
    17       this.State = SessionStates.Done;
    18     }
    19   }
    20   catch (Exception exception)
    21   {
    22     this.State = SessionStates.Aborted;
    23   }
    24   this.Request.ClientPipe = null;
    25   try
    26   {
    27     // this.FinishUISession(false);
    28   }
    29   catch (Exception)
    30   {
    31   }
    32   return flag ;   
    33 }

      找主干,只有三句 (顺便啰嗦一HA,要想学好程序,阅读别人的代码是必不可少的,而阅读 别人代码的法门,就是学会找主干,学会了找主干,就好比练会了独狐九剑,任你纷繁芜杂,俺一眼切中要害)           

    this.Request.ClientPipe.Send(this.Response.Headers.ToByteArray(true, true));
    this.Request.ClientPipe.Send(this.ResponseBodyBytes);
    this.Request.ClientPipe.End();

      还记得封装请求转发给服务端吗

    this.ServerPipe.Send(
      this.m_session.Request.Headers.ToByteArray(
        true, true, this._bWasForwarded && !this.m_session.IsHTTPS
      )
    );
    this.ServerPipe.Send(this.m_session.RequestBodyBytes); 

      两个是不是一样的,只是发送的方向和内容有所不同就是了。各位自行看看代码就明白了。 

      不过这里确实有一点让人 很费解,就是数据发送完成后又加了一句this.Request.ClientPipe.End(); 进去这个方法里看看,其实就是简单的调用Socket.Shutdown和Close把连接给关闭了。这就很奇怪了,前面不是讲,如果客户端,有connection:keep-alive报头,服务端要根据情况判断是否关闭连接吗?另外我们也没有把从服务端接收过来的响应报头里的connection:keep-alive变成connection:close的处理,这也就意味着,响应给客户端的报头里很有可能包含有connection:keep-alive,那不就意味着告诉客户端愿意保持持久连接吗,一方面告诉别人你同意了持久连接,另一方面,又直接把连接给关闭了 ? 这不属于违反协议吗? 当然,这种情况是不属于违反协议的。为什么呢 ? 这是因为,connection:keep-alive保持持久连接并不是承诺性的,双方可以随时在不通知对方的情况下,单方面,关闭连接。也就是说即使服务端的响应报文里包含connection:keep-alive首部或者客户端 的请求报文里含有  connection:keep-alive,这也不代表双方就要百分之百的保证一定会保持持久连接,原因很简单,因为任何情况都有可能会发生,双方也没办法保证,服务器突然当机了、机房突然断电了,客户端在请求过程中,浏览器被关闭了……等等。所以即使双方都认可了connection:keep-alive,并已通知了对方,同意了保持持久连接,这时候在未通知对方关闭的情况下,单方关闭了连接,在HTTP协议中也不算是违约的 

      当然,违不违约,和有没有意义是两回事,在这里,我们直接关闭连接是为了处理方便 , 代理服务器维持持久连接是件很麻烦的事……                  

      终于完成了,额的个神呐,不容易啊。 但在终了,还是要再啰嗦一下,计算机这东西重在理解,上面的代码不要照抄,要在理解的基础上,用自己的方法去实现  

      OKAY,其它的也不罗嗦了,这章到此结束,不过整个系列可还没完。  

      现在只能算拦截完了,篡改还没开始呢。 虽然东方姑娘已经死了,但任大小姐还得继续笑傲江湖呢。                

  • 相关阅读:
    代理模式
    栈和队列----按照左右半区的方式重新组合单链表
    栈和队列----合并两个有序的单链表
    Java中的线程池
    SpringMVC中的参数绑定
    Mybatis常见面试题汇总
    ADC裸机程序
    用uart实现printf函数
    uarts裸机程序
    定时器裸机程序
  • 原文地址:https://www.cnblogs.com/jivi/p/2953647.html
Copyright © 2011-2022 走看看