[C]Safari对websocket的支持及websocket版本问题的解决记

2017-7-11 写技术

昨天有人反应苹果手机不能访问我的物联网项目,我大惊,立马开始分析。

发现果然苹果端的safari连接websocket失败了。但是我确信之前一直用着好好的。可能是贱贱的A厂悄悄变更了某些软件吧,没办法,谁让世人都称他是老大,谁让你们那么多人没有iPhone不行呢。我只好认为我自己的服务器有问题了。

于是检查服务器的日志,发现websocket的握手过程显示协议错误。

那么我抓包分析下safari与其他浏览器的行为有什么不一样吧:

这是Google:


Sec-WebSocket-Key:GX2sEWmKLhgktWvslt8xxw==
Sec-WebSocket-Protocol:mqtt
Sec-WebSocket-Version:13

这是Safari:

Sec-WebSocket-Key1:11684026C 1s7
Sec-WebSocket-Key2:' +8h 5 8  O8%07wc3O8 ! 4E az
Sec-WebSocket-Protocol::mqttv3.1
64:CC:A9:CE:F0:57:34:A4

再明显不过了吧,Safari用的websocket协议是基于MD5加密认证的旧版本,应该是websocket7.1草案协议,而现在的websocket都已经升到13版本了。

显然,我在写服务器的时候是没有去理会过时的websocket版本的。

为了支持苹果设备的websocket,我只能增加版本的支持了。我在我的代码里,增加了对

Sec-WebSocket-Key:

Sec-WebSocket-Key1:

Sec-WebSocket-Key2:

的判断,让其据此进入相应的处理流程,其实也可以去判断获取到的版本号的。

然后增加了返回密钥的函数:

void websocket_accept_key(const char* key,int key_len,char* out){
	char tmp[128]={0};
	unsigned char sha[SHA_DIGEST_LENGTH]={0};
	if(key_len==0){
		key_len=strlen(key);
	}
	strcpy(tmp,key);
	strcpy(tmp+key_len,"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
	SHA1(tmp,key_len+36,sha);
	base64_encode(sha, SHA_DIGEST_LENGTH, out, 256);
}

void websocket_accept_key_safari(const char* key1,int key1Len,const char* key2,int key2Len,char* body,char* out){
	char tmp[16];
	unsigned long long kv1=0;
	unsigned long long kv2=0;
	int c1=0;
	int c2=0;
	int i;
	if(key1Len<=0){
		key1Len=strlen(key1);
	}
	if(key2Len<=0){
		key2Len=strlen(key2);
	}
	for(i=0;i<key1Len;i++){
		if(key1[i]>='0' && key1[i]<='9'){
			kv1=kv1*10+(key1[i]-'0');
		}else if(key1[i]==' '){
			c1++;
		}
	}
	for(i=0;i<key2Len;i++){
		if(key2[i]>='0' && key2[i]<='9'){
			kv2=kv2*10+(key2[i]-'0');
		}else if(key2[i]==' '){
			c2++;
		}
	}

	
	kv1/=c1;
	kv2/=c2;

	*((unsigned long long *)tmp) = htonl(kv1);
	*((unsigned long long *)(tmp+4)) = htonl(kv2);
	
	for(i=0;i<8;i++){
		tmp[i+8]=body[i];
	}

	
	MD5(tmp,16,out);	
	out[16]=0;
}

值得一提的是,在旧版本的websocket协议下,返回密钥是通过body返回的,而在13版本中则是通过Header中的Sec-WebSocket-Access值来返回。

本来到这里,修改工作应该是完成了,然而……

我在windows上装的safari一直测试不能通过。我左改右改地就这么折腾了一天,心累了一天,最后一试苹果手机上的safari居然轻易地连上了!

原来safari也不是每一个版本都支持websocket,我被这个又坑了一把。



标签: ubuntu C linux

发表评论:

Powered by anycle 湘ICP备15001973号