You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
6.1 KiB

  1. #!/usr/bin/env python
  2. # coding: utf-8
  3. from __future__ import unicode_literals
  4. # Allow direct execution
  5. import os
  6. import sys
  7. import unittest
  8. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  9. from youtube_dl import YoutubeDL
  10. from youtube_dl.compat import compat_http_server, compat_urllib_request
  11. import ssl
  12. import threading
  13. TEST_DIR = os.path.dirname(os.path.abspath(__file__))
  14. def http_server_port(httpd):
  15. if os.name == 'java' and isinstance(httpd.socket, ssl.SSLSocket):
  16. # In Jython SSLSocket is not a subclass of socket.socket
  17. sock = httpd.socket.sock
  18. else:
  19. sock = httpd.socket
  20. return sock.getsockname()[1]
  21. class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
  22. def log_message(self, format, *args):
  23. pass
  24. def do_GET(self):
  25. if self.path == '/video.html':
  26. self.send_response(200)
  27. self.send_header('Content-Type', 'text/html; charset=utf-8')
  28. self.end_headers()
  29. self.wfile.write(b'<html><video src="/vid.mp4" /></html>')
  30. elif self.path == '/vid.mp4':
  31. self.send_response(200)
  32. self.send_header('Content-Type', 'video/mp4')
  33. self.end_headers()
  34. self.wfile.write(b'\x00\x00\x00\x00\x20\x66\x74[video]')
  35. elif self.path == '/302':
  36. if sys.version_info[0] == 3:
  37. # XXX: Python 3 http server does not allow non-ASCII header values
  38. self.send_response(404)
  39. self.end_headers()
  40. return
  41. new_url = 'http://localhost:%d/中文.html' % http_server_port(self.server)
  42. self.send_response(302)
  43. self.send_header(b'Location', new_url.encode('utf-8'))
  44. self.end_headers()
  45. elif self.path == '/%E4%B8%AD%E6%96%87.html':
  46. self.send_response(200)
  47. self.send_header('Content-Type', 'text/html; charset=utf-8')
  48. self.end_headers()
  49. self.wfile.write(b'<html><video src="/vid.mp4" /></html>')
  50. else:
  51. assert False
  52. class FakeLogger(object):
  53. def debug(self, msg):
  54. pass
  55. def warning(self, msg):
  56. pass
  57. def error(self, msg):
  58. pass
  59. class TestHTTP(unittest.TestCase):
  60. def setUp(self):
  61. self.httpd = compat_http_server.HTTPServer(
  62. ('localhost', 0), HTTPTestRequestHandler)
  63. self.port = http_server_port(self.httpd)
  64. self.server_thread = threading.Thread(target=self.httpd.serve_forever)
  65. self.server_thread.daemon = True
  66. self.server_thread.start()
  67. def test_unicode_path_redirection(self):
  68. # XXX: Python 3 http server does not allow non-ASCII header values
  69. if sys.version_info[0] == 3:
  70. return
  71. ydl = YoutubeDL({'logger': FakeLogger()})
  72. r = ydl.extract_info('http://localhost:%d/302' % self.port)
  73. self.assertEqual(r['url'], 'http://localhost:%d/vid.mp4' % self.port)
  74. class TestHTTPS(unittest.TestCase):
  75. def setUp(self):
  76. certfn = os.path.join(TEST_DIR, 'testcert.pem')
  77. self.httpd = compat_http_server.HTTPServer(
  78. ('localhost', 0), HTTPTestRequestHandler)
  79. self.httpd.socket = ssl.wrap_socket(
  80. self.httpd.socket, certfile=certfn, server_side=True)
  81. self.port = http_server_port(self.httpd)
  82. self.server_thread = threading.Thread(target=self.httpd.serve_forever)
  83. self.server_thread.daemon = True
  84. self.server_thread.start()
  85. def test_nocheckcertificate(self):
  86. if sys.version_info >= (2, 7, 9): # No certificate checking anyways
  87. ydl = YoutubeDL({'logger': FakeLogger()})
  88. self.assertRaises(
  89. Exception,
  90. ydl.extract_info, 'https://localhost:%d/video.html' % self.port)
  91. ydl = YoutubeDL({'logger': FakeLogger(), 'nocheckcertificate': True})
  92. r = ydl.extract_info('https://localhost:%d/video.html' % self.port)
  93. self.assertEqual(r['url'], 'https://localhost:%d/vid.mp4' % self.port)
  94. def _build_proxy_handler(name):
  95. class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
  96. proxy_name = name
  97. def log_message(self, format, *args):
  98. pass
  99. def do_GET(self):
  100. self.send_response(200)
  101. self.send_header('Content-Type', 'text/plain; charset=utf-8')
  102. self.end_headers()
  103. self.wfile.write('{self.proxy_name}: {self.path}'.format(self=self).encode('utf-8'))
  104. return HTTPTestRequestHandler
  105. class TestProxy(unittest.TestCase):
  106. def setUp(self):
  107. self.proxy = compat_http_server.HTTPServer(
  108. ('localhost', 0), _build_proxy_handler('normal'))
  109. self.port = http_server_port(self.proxy)
  110. self.proxy_thread = threading.Thread(target=self.proxy.serve_forever)
  111. self.proxy_thread.daemon = True
  112. self.proxy_thread.start()
  113. self.geo_proxy = compat_http_server.HTTPServer(
  114. ('localhost', 0), _build_proxy_handler('geo'))
  115. self.geo_port = http_server_port(self.geo_proxy)
  116. self.geo_proxy_thread = threading.Thread(target=self.geo_proxy.serve_forever)
  117. self.geo_proxy_thread.daemon = True
  118. self.geo_proxy_thread.start()
  119. def test_proxy(self):
  120. geo_proxy = 'localhost:{0}'.format(self.geo_port)
  121. ydl = YoutubeDL({
  122. 'proxy': 'localhost:{0}'.format(self.port),
  123. 'geo_verification_proxy': geo_proxy,
  124. })
  125. url = 'http://foo.com/bar'
  126. response = ydl.urlopen(url).read().decode('utf-8')
  127. self.assertEqual(response, 'normal: {0}'.format(url))
  128. req = compat_urllib_request.Request(url)
  129. req.add_header('Ytdl-request-proxy', geo_proxy)
  130. response = ydl.urlopen(req).read().decode('utf-8')
  131. self.assertEqual(response, 'geo: {0}'.format(url))
  132. def test_proxy_with_idn(self):
  133. ydl = YoutubeDL({
  134. 'proxy': 'localhost:{0}'.format(self.port),
  135. })
  136. url = 'http://中文.tw/'
  137. response = ydl.urlopen(url).read().decode('utf-8')
  138. # b'xn--fiq228c' is '中文'.encode('idna')
  139. self.assertEqual(response, 'normal: http://xn--fiq228c.tw/')
  140. if __name__ == '__main__':
  141. unittest.main()