zoukankan      html  css  js  c++  java
  • AJP协议总结与分析

    Tomcat服务器通过Connector连接器组件与客户程序建立连接,Connector组件负责接收客户的请求,以及把Tomcat服务器的响应结果发送给客户。默认情况下,Tomcat在server.xml中配置了两种连接器:
      
      <!-- Define a non-SSL Coyote HTTP/1.1
      Connector on port 8080 -->
      <Connector port="8080"
      maxThreads="150"
      minSpareThreads="25"
      maxSpareThreads="75"
      enableLookups="false"
      redirectPort="8443"
      acceptCount="100"
      debug="0"
      connectionTimeout="20000"
      disableUploadTimeout="true" />
      
      <!-- Define a Coyote/JK2 AJP 1.3
      Connector on port 8009 -->
      <Connector port="8009"
      enableLookups="false"
      redirectPort="8443" debug="0"
      protocol="AJP/1.3" />
      
      第一个连接器监听8080端口,负责建立HTTP连接。在通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个

    http://blog.sina.com.cn/s/blog_6870d1e00100mv64.html

    一般Tomcat默认的SSL端口号是8443,但是对于SSL标准端口号是443,这样在访问网页的时候,直接使用https而不需要输入端口号就可以访问,如https://ip/ 
    想要修改端口号,需要修改Tomcat的server.xml文件: 
    1.non-SSL HTTP/1.1 Connector定义的地方,一般如下: 
         <Connector port="80" maxHttpHeaderSize="8192" 
                    maxThreads="500" minSpareThreads="25" maxSpareThreads="75" 
                    enableLookups="false" redirectPort="443" acceptCount="100" 
                    connectionTimeout="20000" disableUploadTimeout="true" /> 
    将其中的redirectPort端口号改为:443 
    2.SSL HTTP/1.1 Connector定义的地方,修改端口号为:443,如下: 
    <Connector     
       port="443" maxHttpHeaderSize="8192" 
       maxThreads="150" minSpareThreads="25" 
       maxSpareThreads="75" 
       enableLookups="false" 
       disableUploadTimeout="true" 
       acceptCount="100" scheme="https" 
       secure="true" 
       clientAuth="false" sslProtocol="TLS" 
       keystoreFile="conf/tomcat.keystore" 
       keystorePass="123456" /> 
    3.AJP 1.3 Connector定义的地方,修改redirectPort为443,如下: 
         <Connector port="8009" 
                    enableLookups="false" redirectPort="443" protocol="AJP/1.3" /> 

    重新启动Tomcat就可以了。到这一步可以形成访问方式 https://ip/

    4、强制https访问

      在tomcatconfweb.xml中的</welcome-file-list>后面加上这样一段:

    <login-config>  
        <!-- Authorization setting for SSL -->  
        <auth-method>CLIENT-CERT</auth-method>  
        <realm-name>Client Cert Users-only Area</realm-name>  
    </login-config>  
    <security-constraint>  
        <!-- Authorization setting for SSL -->  
        <web-resource-collection >  
            <web-resource-name >SSL</web-resource-name>  
            <url-pattern>/*</url-pattern>  
        </web-resource-collection>  
        <user-data-constraint>  
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>  
        </user-data-constraint>  
    </security-constraint> 

    注意:(如果对方使用的机器端口被占用)

    需要切换端口来转换数据:iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

    AJP(Apache JServ Protocol)是定向包协议。因为性能原因,使用二进制格式来传输可读性文本。WEB服务器通过TCP连接和SERVLET容器连接。

    (格式显示不好,本文已放附件中)

    AJP协议是定向包(面向包)协议,采用二进制形式代替文本形式,以提高性能。Web Server一般维持和Web Container的多个TCP Connecions,即TCP连接池,多个request/respons循环重用同一个Connection。但是当Connection被分配(Assigned)到某个请求时,该请求完成之前,其他请求不得使用该连接。

    Tcp Connection 具有两种状态:

    (1). Idle
    没有请求正使用该连接。
    (2). Assigned
    当前连接正在处理某个请求.
     
    数据类型:
     AJP协议中包括四种数据类型:Byte, Boolean, Integer and String.
     Byte: 一个字节

      Boolean: 一个字节,1 = true, 0 = false。

     Integer:两个字节,无符号整数,高位字节在前。
     String:可变字符串,最大长度为2^16. 字符串的前而会有二个字节(Integer型)表示字符串的长度,-1表示null。字符串后面会跟上终结符””,而且字符串长度不包括这个终结符。
     
    AJP的包结构,图表1:
    包方向
    0
    1
    2
    3
    4…(n+3)
    Server->Container
    0x12
    0x34
    数据长度(n)
    数据(payload)
    Container->Server
    A
    B
    数据长度(n)
    数据(payload)
                           图表1
    可以看出,从apache发向tomcat包都带有0x1234头,而从tomcat发向apache的包都带有AB(ascii码)头,随后二字节代表数据的长度(不包括前四个字节).所认AJP包的最大长度可以接近2^16,但目前的版本支持的最大包长度为2^13,即8K。
     
    再看数据部分(payload),除Server->Container的请求体包外,其他包的数据部分的首字节为其消息类型(code),如下表(描述部分是原文,译成中文本人认为更难理解,英文表义比中文是好一些):
    方向
    code
    包类型
    描述
    Server->Container
    2

    Forward Request

    Begin the request-processing cycle with the following data。

    7
    Shutdown

    The web server asks the container to shut itself down

    8
    Ping

    The web server asks the container to take control (secure login phase).

    10
    Cping

    The web server asks the container to respond quickly with a CPong

    none
    Data

    Size (2 bytes) and corresponding body data.

    Container->Server
    3
    Send Body Chunk

    Send a chunk of the body from the servlet container to the web server

    4
    Send Headers

    Send the response headers from the servlet container to the web server

    5
    End Response
    Marks the end of the response
    6
    Get Body Chunk

    Get further data from the request if it hasn't all been transferred yet

    9
    CPong Reply
    The reply to a CPing request
    Forward Request包数据部分(payload)结构:
    AJP13_FORWARD_REQUEST :=
        prefix_code      (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
        method           (byte)
        protocol         (string)
        req_uri          (string)
        remote_addr      (string)
        remote_host      (string)
        server_name      (string)
        server_port      (integer)
        is_ssl           (boolean)
        num_headers      (integer)

        request_headers *(req_header_name req_header_value)

        attributes      *(attribut_name attribute_value)

    request_terminator (byte) OxFF

    ---------------------------------------------------------------------------------------------------------------------------------
    req_header_name :=

    sc_req_header_name | (string) [see below for how this is parsed]

    ---------------------------------------------------------------------------------------------------------------------------------

    sc_req_header_name := 0xA0xx (integer)

    req_header_value := (string)
    ---------------------------------------------------------------------------------------------------------------------------------

    attribute_name := sc_a_name | (sc_a_req_attribute string)

    attribute_value := (string)
     

    (1)     prefix_code 所有的Forward Request包都是0x02.

    (2)     Method: 一个字节,对方法的编码,其对应如下(只列了部分):

    Command Name

    code
    POST      
    4
    OPTIONS 
    1
    PUT       
    5
    GET     
    2
    DELETE   
    6
    HEAD    
    3
    TRACE    
    7
    (参考:http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html)
     

    (3)     protocol, req_uri, remote_addr, remote_host, server_name, server_port, is_ssl: 每个请求包都有这几个字段,格式都是 长度+字符串值+结束符。

    (4)     num_headers: 请求头的个数,两个字节。
    (5)     request_headers:
    请求头名称分化为两类,一类请求头被转换为0xA0xx格式(如下表所示),其他请求头仍然用原字符串编码。
     
    请求头

    Code 值

    Code 名称

    accept

    0xA001
    SC_REQ_ACCEPT
    accept-charset
    0xA002
    SC_REQ_ACCEPT_CHARSET
    accept-encoding
    0xA003
    SC_REQ_ACCEPT_ENCODING
    accept-language
    0xA004
    SC_REQ_ACCEPT_LANGUAGE
    authorization
    0xA005
    SC_REQ_AUTHORIZATION
    connection
    0xA006
    SC_REQ_CONNECTION
    content-type
    0xA007
    SC_REQ_CONTENT_TYPE
    content-length
    0xA008
    SC_REQ_CONTENT_LENGTH
    cookie
    0xA009
    SC_REQ_COOKIE
    cookie2
    0xA00A
    SC_REQ_COOKIE2
    host
    0xA00B

    SC_REQ_HOST 0xA00C

    pragma
    0xA00C
    SC_REQ_PRAGMA
    referer
    0xA00D
    SC_REQ_REFERER
    user-agent
    0xA00E
    SC_REQ_USER_AGENT
    (6)     Java代码读取头两个字节的整数型,如果高位字节为”0xA0” ,则第二字节为上在列表的索引。如果高位字节不是”0xA0”,则这两个字节为随后请求头名称的长度。
    (7)     Attributes:很少用,直接看tomcat文档吧。     
    (8)     request_terminator: 一个字节0xFF,请求结束符。
     
    响应包数据部分(payload)结构:
    AJP13_SEND_HEADERS :=
     prefix_code       4
     http_status_code (integer)
     http_status_msg   (string)
     num_headers       (integer)

     response_headers *(res_header_name header_value)

     
    res_header_name :=
        sc_res_header_name | (string)   [see below for how this is parsed]
     

    sc_res_header_name := 0xA0 (byte)

    header_value := (string)
     
    AJP13_SEND_BODY_CHUNK :=
     prefix_code   3
     chunk_length (integer)

     chunk        *(byte)

     
    AJP13_END_RESPONSE :=
     prefix_code       5
     reuse             (boolean)
     
    AJP13_GET_BODY_CHUNK :=
     prefix_code       6
     requested_length (integer)
     
    1.       response_headers: 和请求头一样,一类响应头被转换为0xA0xx格式(如下表所示),其他响应头名称采用原字符串编码。
    请求头

    Code 值

    Code 名称

    Content-Type
    0xA001
    SC_RESP_CONTENT_TYPE
    Content-Language
    0xA002
    SC_RESP_CONTENT_LANGUAGE
    Content-Length
    0xA003
    SC_RESP_CONTENT_LENGTH
    Date
    0xA004
    SC_RESP_DATE
    Last-Modified
    0xA005
    SC_RESP_LAST_MODIFIED
    Location
    0xA006
    SC_RESP_LOCATION
    Set-Cookie
    0xA007
    SC_RESP_SET_COOKIE
    Set-Cookie2
    0xA008
    SC_RESP_SET_COOKIE2
    Servlet-Engine
    0xA009
    SC_RESP_SERVLET_ENGINE
    Status
    0xA00A
    SC_RESP_STATUS
    WWW-Authenticate
    0xA00B
    SC_RESP_WWW_AUTHENTICATE
    2.       reuse: 如果为1,表示该连接可以被子重用,否则这个连接应该关闭。
     
    下面我们来看一个简单AJP请求过程中抓到的请求包:
     

    1,2字节是上文所说的Server->Container包头,3,4字节表示包长度(0x01b0=432),即从第5个字节到最后的一个字节(ff)的长度。第5个字节(02)代表是”Forward Request”包。
    第6个字节(02)代表是Get请求。第7,8字节(0x0008)代表protocol字符串的长度,后8个字节为protocol字符串(HTTP/1.1),第9个字节为protocol字符串的终结符“”。
    18-41字节代表req_uri字符串(0x15+2+1=24个)。
    42-53字节代表remote_addr字符串(0x09+2+1=12个)
    54-55 两字节(0xffff=-1)代表null字符串,即remote_host不存在。
    56-67两字节代表server_name字符串(0x09+2+1=12个)
    68-69两字节(0x0050=80)代表server_port
    70字节(0x00)代表is_ssl为false
    71-72两字节(0x0009)代表该请求有9个请求头,如图中的前9个红色椭圆.
    第10个红色椭圆(0x06)代表Attributes的route.
    第11个红椭圆之后,代表AJP_REMOTE_PORT与JK_LB_ACTIVATION两个请求属性.
    最后一个字节0xFF表示请求结束。
    响应头数据包:
     

    和请示头比较类似,不再细描述。其中第5个字节0x04代表”Send Headers”响应。
    并且没有终结符字节0xFF.
     
    响应正文数据包:

     响应结束End Response:
     
    其中最后一个字节(01),代表当前连接仍然可用。
    (完)

    http://guojuanjun.blog.51cto.com/277646/688559/

  • 相关阅读:
    创建HttpFilter与理解多个Filter代码的执行顺序
    Filter
    JSTL
    EL
    JavaBean
    HttpSession之表单的重复提交 & 验证码
    相对路径和绝对路径
    HttpSession之简易购物车
    HttpSession
    Cookie
  • 原文地址:https://www.cnblogs.com/softidea/p/5735102.html
Copyright © 2011-2022 走看看