nginx源码分析之header小写问题以及C开源项目调试技巧

写在前面

我为什么要写博客,总感觉东西是自己,知道就知道了。为什么一定要写下来呢?
我也不知道。

前言

nginx开启HTTP2模式下 header头全部小写,导致前端取header头出错。
HTTP2模式下,header会压缩,并采用霍夫曼编码的压缩方式。推测可能,HTTP2
如果header头大小写敏感的话,可能压缩效果不是很好。为什么?组合数学,信息论?
此不在本文讨论范畴。header头为什么会小写,这些不是nginx的东西,这些是HTTP2协议的规范,nginx只是实现而已。

本机环境

Linux wwx-desktop 4.15.0-54-generic #58~16.04.1-Ubuntu SMP Mon Jun 24 13:21:41 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

nginx调试

nginx调试有点特别,因为nginx不仅会启动main方法,还会在main方法中fork子进程,

俗称nginx的工作进程,可能fork多个子进程,仅从nginx配置可窥知一二。
默认gdb调试配置,
是不会进入子进程的断点的,所以gdb调试需要用到以下两个命令


set detach-on-fork off
set follow-fork-mode child

步骤

  • 下载nginx源码文件http://nginx.org/en/download.html,选择1.10.3版本以上,因为至此开始
    nginx才支持HTTP2协议。源码目录
    nginx源码分析之header小写问题以及C开源项目调试技巧_第1张图片
  • 简单编译安装只需要两个命令:
./configure --prefix=/usr/local/nginx  
--with-http_stub_status_module 
--with-http_ssl_module 
--with-http_v2_module --with-debug
make install

第一个命令解释如下:nginx高性能,你用哪些模块我就编译哪些模块,所以nginx不会主动编译所有模块。
至于–with-debug,nginx不会主动把debug模块加入进去,如果你想nginx支持日志级别debug你也要编译进去。

  • 记录一些编译的时候的日志输出:
    在我们执行第二个步骤的第一个命令的时候,nginx会在源码的根目录创建文件夹objs,并生成三个重要的文件
    /home/nginx-1.10.3/objs/ngx_auto_config.h
    /home/nginx-1.10.3/objs/ngx_auto_headers.h
    /home/nginx-1.10.3/objs/ngx_modules.c
    这些文件在以后的编译都会用到。
    在执行第二个命令的时候,makefile会打印这样一条链接的日志输出:
...
objs/src/http/modules/ngx_http_stub_status_module.o \
objs/ngx_modules.o \
-ldl -lpthread -lcrypt -lpcre -lssl -lcrypto -ldl -lz \
-Wl,-E
...

这个以后也会用到。

  • 把代码移植到clion ide中,clion是什么?我是JetBrains的铁粉。

移植后的目录如下:
nginx源码分析之header小写问题以及C开源项目调试技巧_第2张图片

cmake是什么?自行百度,这里面我简单提一下几个配置说明:
nginx源码分析之header小写问题以及C开源项目调试技巧_第3张图片nginx源码分析之header小写问题以及C开源项目调试技巧_第4张图片

  1. ADD_DEFINITIONS() 宏定义为空,因为nginx所欲宏的预定义都在自动生成的两个个头文件里面
    对应的就是
    /home/nginx-1.10.3/objs/ngx_auto_config.h
    /home/nginx-1.10.3/objs/ngx_auto_headers.h
  2. TARGET_LINK_LIBRARIES(nginx_1_10_3 -ldl -lpthread -lcrypt -lssl -lpcre -lcrypto -lcrypto -lz)
    为什么这么写,参见make install日志输出即可。
  3. SET(SOURCE_FILES …) nginx源文件包含哪些,有些不需要就不要写进去,比如
    在src/event/modules/有如下一下网络模型文件并区分操作系统:
    ngx_devpoll_module.c
    ngx_epoll_module.c
    ngx_eventport_module.c
    ngx_kqueue_module.c
    ngx_poll_module.c
    ngx_select_module.c
    ngx_win32_select_module.c

为什么我知道要用第二个文件?很简单,你去你的objs对应的目录下查看存在哪些.o文件即可。
4. cmake命令大小写不敏感

  • 开始debug

几点配置直接上图
nginx源码分析之header小写问题以及C开源项目调试技巧_第5张图片
编写nginx.conf

worker_processes  1;
daemon off;
error_log  /home/nginx-1.10.3/logs/error.log  debug;
error_log  /dev/stdout  debug;

worker_processes 1;我不知道配置多个工作进程,clion在debug的时候会出现什么怪异现象。
daemon off;ngnix前台启动,方便debug断点。
error_log /dev/stdout debug;nginx日志输出到标准输出上面。就是控制台啦。



    upstream book_pool{
        server 127.0.0.1:8081;
    }
    server {

        access_log  /home/nginx-1.10.3/logs/host.access.log  main;
        access_log  /dev/stdout  main;

        listen       80;

        server_name  lbs.test.com;

        listen 443 ssl http2;
        ssl_certificate   /home/py/cert.crt;
        ssl_certificate_key  /home/py/rsa_private.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
        ssl_prefer_server_ciphers on;

开启ssl和http2。
关于
ssl_certificate /home/py/cert.crt;
ssl_certificate_key /home/py/rsa_private.key;
自行百度即可。

断点一定要打在main还没有fork子进程之前,如下如图:
nginx源码分析之header小写问题以及C开源项目调试技巧_第6张图片
然后打开gdb,依次输入以下命令,并放开断点即可

set detach-on-fork off
set follow-fork-mode child

nginx源码分析之header小写问题以及C开源项目调试技巧_第7张图片
命令含义:
GDB默认调试的是只跟进父进程,是由follow-fork-mode(fork跟进模式)和detach-on-fork
(是否分离两个进程)共同决定的,他们的作用效果见下:

follow-fork-mode detach-on-fork 功能
parent on 只调试父进程(默认)
child on 只调试子进程
parent off 调试两个进程,跟进父进程,子进程阻塞在fork处
child off 调试两个进程,跟进子进程,父进程阻塞在fork处

nginx源码分析之header小写问题以及C开源项目调试技巧_第8张图片

  • 编写python3简单web脚本
from http.server import HTTPServer, BaseHTTPRequestHandler

class MyHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        self.send_response(200)
        self.send_header('Lbs_Channel', 'QuickApp')
        self.end_headers()
        self.wfile.write(b'hello world')
        return


if __name__ == '__main__':
    try:
        server = HTTPServer(('', 8081), MyHandler)
        server.serve_forever()
    except KeyboardInterrupt:
        print
        '^c received,shutting down the web server!'
        server.socket.close()

启动之。

  • 你可以在浏览器输入http://lbs.test.com/ 或者https://lbs.test.com/
    查看分析nginx在不同的情况下处理流程,http1和http2还是很有区别的。
    本文目的不在这,主要分析在http2下header小写的问题。

debug关键位置
nginx源码分析之header小写问题以及C开源项目调试技巧_第9张图片nginx源码分析之header小写问题以及C开源项目调试技巧_第10张图片
nginx源码分析之header小写问题以及C开源项目调试技巧_第11张图片nginx源码分析之header小写问题以及C开源项目调试技巧_第12张图片
nginx源码分析之header小写问题以及C开源项目调试技巧_第13张图片
nginx源码分析之header小写问题以及C开源项目调试技巧_第14张图片
从上问的处理流程可看出问题霍夫曼编码的存在。
header压缩,采用huff编码,nginx静态huff编码方式。
在HTTP2中使用的是静态Huffman编码。Huffman编码按理说应该不属于计算机,
而是信息论的东西,这里不细说。对于HTTP2,查表即可。
表格地址:https://tools.ietf.org/html/rfc7541#appendix-B

调试项目 github 地址:https://github.com/wwxname/nginx-debug.git

结束
撒花 撒花
enjoy it

你可能感兴趣的:(nginx,c,clion,debug)