Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过https下载文件时出现SSL错误_Ssl_Https_Common Lisp - Fatal编程技术网

通过https下载文件时出现SSL错误

通过https下载文件时出现SSL错误,ssl,https,common-lisp,Ssl,Https,Common Lisp,我需要从下载quicklisp.lisp的最新版本 首先,我在代码中使用常见的lisp库usocket和cl+ssl尝试下载html页面,它可以正常工作 (usocket:with-client-socket (sock stream "quicklisp.org" 443) (let ((https (cl+ssl:make-ssl-client-stream stream :unwrap-stream-p t :extern

我需要从下载quicklisp.lisp的最新版本

首先,我在代码中使用常见的lisp库usocket和cl+ssl尝试下载html页面,它可以正常工作

(usocket:with-client-socket (sock stream "quicklisp.org" 443)
  (let ((https (cl+ssl:make-ssl-client-stream
                stream :unwrap-stream-p t
                :external-format '(:iso-8859-1 :eol-style :lf))))
    (unwind-protect
         (progn
           (format https "GET /beta/ HTTP/1.0~%Host:www.quicklisp.org~%Connection:keep-alive~2%")
           (force-output https)
           (loop for line = (read-line https nil)
              while line do (format t "HTTPS> ~a~%" line)))
      (close https))))
然后,我稍微修改了上面quicklisp.lisp文件的代码:

(usocket:with-client-socket (sock stream "beta.quicklisp.org" 443)
  (let ((https (cl+ssl:make-ssl-client-stream
                stream :unwrap-stream-p t
                :external-format '(:iso-8859-1 :eol-style :lf))))
    (unwind-protect
         (progn
           (format https "GET /quicklisp.lisp HTTP/1.1~%Host:beta.quicklisp.org~%Connection:keep-alive~%Accept: */*~2%")
           (force-output https)
           (loop for line = (read-line https nil)
              while line do (format t "HTTPS> ~a~%" line)))
      (close https))))
这一次,它失败了,没有运气。错误消息显示:

A failure in the SSL library occurred on handle #.(SB-SYS:INT-SAP #X7FFFDC019A80) (return code: 1).
SSL error queue:
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
   [Condition of type CL+SSL::SSL-ERROR-SSL]

Restarts:
 0: [RETRY] Retry SLIME interactive evaluation request.
 1: [*ABORT] Return to SLIME's top level.
 2: [ABORT] abort thread (#<THREAD "worker" RUNNING {10088E6223}>)

Backtrace:
  0: (CL+SSL::SSL-SIGNAL-ERROR #.(SB-SYS:INT-SAP #X7FFFDC019A80) #<FUNCTION CL+SSL::SSL-CONNECT> 1 -1)
      Locals:
        ERROR-CODE = 1
        HANDLE = #.(SB-SYS:INT-SAP #X7FFFDC019A80)
        ORIGINAL-ERROR = -1
        SYSCALL = #<FUNCTION CL+SSL::SSL-CONNECT>
  1: (CL+SSL:MAKE-SSL-CLIENT-STREAM #<unavailable lambda list>)
      [No Locals]
  2: ((LAMBDA ()))
  3: (SB-INT:SIMPLE-EVAL-IN-LEXENV (USOCKET:WITH-CLIENT-SOCKET (SOCK STREAM "beta.quicklisp.org" 443) (LET (#) (UNWIND-PROTECT # #))) #<NULL-LEXENV>)
  4: (EVAL (USOCKET:WITH-CLIENT-SOCKET (SOCK STREAM "beta.quicklisp.org" 443) (LET (#) (UNWIND-PROTECT # #))))
  5: ((LAMBDA NIL :IN SWANK:INTERACTIVE-EVAL))
句柄#(SB-SYS:INT-SAP#X7FFFDC019A80)(返回代码:1)上的SSL库发生故障。
SSL错误队列:
错误:14077410:SSL例程:SSL23\u GET\u SERVER\u HELLO:sslv3警报握手失败
[CL+SSL类型的条件::SSL-ERROR-SSL]
重新启动:
0:[重试]重试SLIME交互式评估请求。
1:[*中止]返回SLIME的顶层。
2:[中止]中止线程(#)
回溯:
0:(CL+SSL::SSL-SIGNAL-ERROR#(SB-SYS:INT-SAP#X7FFFDC019A80)#1-1)
当地人:
错误代码=1
句柄=#(SB-SYS:INT-SAP#X7FFFDC019A80)
原始错误=-1
系统调用=#
1:(CL+SSL:MAKE-SSL-CLIENT-STREAM#)
[没有本地人]
2:((LAMBDA()))
3:(SB-INT:SIMPLE-EVAL-IN-lexev(USOCKET:WITH-CLIENT-SOCKET(SOCK STREAM“beta.quicklisp.org”443)(LET(#)(UNWIND-PROTECT#)#)
4:(EVAL(USOCKET:WITH-CLIENT-SOCKET(SOCK STREAM“beta.quicklisp.org”443)(LET(#)(UNWIND-PROTECT#))
5:((LAMBDA NIL:IN-SWANK:INTERACTIVE-EVAL))

我知道还有另一个常见的lisp库,drakma可以在这里做我需要的事情。但我只是好奇为什么我的方法会失败?

我不熟悉common lisp中的SSL是如何工作的,但从中可以看出,
beta.quicklistp.org
仅在客户端使用时有效,而您的工作示例中的
quicklistp.org
不需要SNI

如果我正确地解释了您的代码,您首先创建到目标主机的TCP连接,然后围绕此连接包装TLS。由于在进行此包装时您没有提供任何有关目标主机名的信息,因此我假设TLS包装器不会知道主机名,因此无法在TLS握手中告诉服务器请求的主机名,即它无法使用SNI。由于服务器需要SNI,因此连接将失败

有一种方法可以指定主机名。从文件中:

Function CL+SSL:MAKE-SSL-CLIENT-STREAM 
(fd-or-stream &key 
   external-format certificate key password close-callback 
   (unwrap-streams-p t) 
   hostname
 )
 ...
 hostname if specified, will be sent by client during TLS negotiation, 
 according to the Server Name Indication (SNI) extension to the TLS. 

除此之外:
您正在执行
HTTP/1.1
请求,但无法正确处理
HTTP/1.1
响应,如分块编码。对于像您这样的简单请求,我建议只使用
HTTP/1.0
。此外,您的代码期望服务器在数据传输完成后关闭连接,也就是说,您不从HTTP头提取正文大小,而只读取给定的字节数。在这种情况下使用
Connection:keep alive
是一个坏主意,因为这种方法要求服务器在发送正文后保持连接打开。另外,
Connection:keep alive
在使用
HTTP/1.1
时是隐式的。

根据Steffen的精彩解释,我找到了让它工作的方法:

(usocket:with-client-socket (sock stream "beta.quicklisp.org" 443)
  (let ((https (cl+ssl:make-ssl-client-stream
                stream :unwrap-stream-p t
                :external-format '(:iso-8859-1 :eol-style :lf)
                :hostname "beta.quicklisp.org")))
    (unwind-protect
         (progn
           (format https "GET /quicklisp.lisp HTTP/1.0~%Host:beta.quicklisp.org~%Accept: */*~2%")
           (force-output https)
           (loop for line = (read-line https nil)
              while line do (format t "HTTPS> ~a~%" line)))
      (close https))))

谢谢,Steffen。

你能用
curl
来获取文件吗?它们是否使用相同的ssl版本?(哪个?)从我能找到的来看,我怀疑这是一个口齿不清的错误。(还有:为什么要从
HTTP/1.0
更改为
HTTP/1.1
?)对于从HTTP/1.0更改为HTTP/1.1,既然我在HTTP/1.0上失败了,只想切换到HTTP/1.1再做一次尝试,Steffen谢谢你的精彩解释。我用添加的主机名修改代码,然后它就可以工作了。