mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Removed the related code of gem server
This commit is contained in:
parent
1d88eec8e3
commit
4a39167260
4 changed files with 18 additions and 1613 deletions
|
@ -1,88 +1,25 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
require_relative '../command'
|
require_relative '../command'
|
||||||
require_relative '../server'
|
|
||||||
require_relative '../deprecate'
|
|
||||||
|
|
||||||
class Gem::Commands::ServerCommand < Gem::Command
|
unless defined? Gem::Commands::ServerCommand
|
||||||
extend Gem::Deprecate
|
class Gem::Commands::ServerCommand < Gem::Command
|
||||||
rubygems_deprecate_command
|
def initialize
|
||||||
|
super('server', 'Starts up a web server that hosts the RDoc (requires rubygems-server)')
|
||||||
def initialize
|
begin
|
||||||
super 'server', 'Documentation and gem repository HTTP server',
|
Gem::Specification.find_by_name('rubygems-server').activate
|
||||||
:port => 8808, :gemdir => [], :daemon => false
|
rescue Gem::LoadError
|
||||||
|
# no-op
|
||||||
OptionParser.accept :Port do |port|
|
|
||||||
if port =~ /\A\d+\z/
|
|
||||||
port = Integer port
|
|
||||||
raise OptionParser::InvalidArgument, "#{port}: not a port number" if
|
|
||||||
port > 65535
|
|
||||||
|
|
||||||
port
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
Socket.getservbyname port
|
|
||||||
rescue SocketError
|
|
||||||
raise OptionParser::InvalidArgument, "#{port}: no such named service"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
add_option '-p', '--port=PORT', :Port,
|
def description # :nodoc:
|
||||||
'port to listen on' do |port, options|
|
<<-EOF
|
||||||
options[:port] = port
|
The server command has been moved to the rubygems-server gem.
|
||||||
|
EOF
|
||||||
end
|
end
|
||||||
|
|
||||||
add_option '-d', '--dir=GEMDIR',
|
def execute
|
||||||
'directories from which to serve gems',
|
alert_error "Install the rubygems-server gem for the server command"
|
||||||
'multiple directories may be provided' do |gemdir, options|
|
|
||||||
options[:gemdir] << File.expand_path(gemdir)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
add_option '--[no-]daemon', 'run as a daemon' do |daemon, options|
|
|
||||||
options[:daemon] = daemon
|
|
||||||
end
|
|
||||||
|
|
||||||
add_option '-b', '--bind=HOST,HOST',
|
|
||||||
'addresses to bind', Array do |address, options|
|
|
||||||
options[:addresses] ||= []
|
|
||||||
options[:addresses].push(*address)
|
|
||||||
end
|
|
||||||
|
|
||||||
add_option '-l', '--launch[=COMMAND]',
|
|
||||||
'launches a browser window',
|
|
||||||
"COMMAND defaults to 'start' on Windows",
|
|
||||||
"and 'open' on all other platforms" do |launch, options|
|
|
||||||
launch ||= Gem.win_platform? ? 'start' : 'open'
|
|
||||||
options[:launch] = launch
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def defaults_str # :nodoc:
|
|
||||||
"--port 8808 --dir #{Gem.dir} --no-daemon"
|
|
||||||
end
|
|
||||||
|
|
||||||
def description # :nodoc:
|
|
||||||
<<-EOF
|
|
||||||
The server command starts up a web server that hosts the RDoc for your
|
|
||||||
installed gems and can operate as a server for installation of gems on other
|
|
||||||
machines.
|
|
||||||
|
|
||||||
The cache files for installed gems must exist to use the server as a source
|
|
||||||
for gem installation.
|
|
||||||
|
|
||||||
To install gems from a running server, use `gem install GEMNAME --source
|
|
||||||
http://gem_server_host:8808`
|
|
||||||
|
|
||||||
You can set up a shortcut to gem server documentation using the URL:
|
|
||||||
|
|
||||||
http://localhost:8808/rdoc?q=%s - Firefox
|
|
||||||
http://localhost:8808/rdoc?q=* - LaunchBar
|
|
||||||
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute
|
|
||||||
options[:gemdir] = Gem.path if options[:gemdir].empty?
|
|
||||||
Gem::Server.run options
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,882 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
require 'zlib'
|
|
||||||
require 'erb'
|
|
||||||
require 'uri'
|
|
||||||
|
|
||||||
require_relative '../rubygems'
|
|
||||||
require_relative 'rdoc'
|
|
||||||
|
|
||||||
##
|
|
||||||
# Gem::Server and allows users to serve gems for consumption by
|
|
||||||
# `gem --remote-install`.
|
|
||||||
#
|
|
||||||
# gem_server starts an HTTP server on the given port and serves the following:
|
|
||||||
# * "/" - Browsing of gem spec files for installed gems
|
|
||||||
# * "/specs.#{Gem.marshal_version}.gz" - specs name/version/platform index
|
|
||||||
# * "/latest_specs.#{Gem.marshal_version}.gz" - latest specs
|
|
||||||
# name/version/platform index
|
|
||||||
# * "/quick/" - Individual gemspecs
|
|
||||||
# * "/gems" - Direct access to download the installable gems
|
|
||||||
# * "/rdoc?q=" - Search for installed rdoc documentation
|
|
||||||
#
|
|
||||||
# == Usage
|
|
||||||
#
|
|
||||||
# gem_server = Gem::Server.new Gem.dir, 8089, false
|
|
||||||
# gem_server.run
|
|
||||||
#
|
|
||||||
#--
|
|
||||||
# TODO Refactor into a real WEBrick servlet to remove code duplication.
|
|
||||||
|
|
||||||
class Gem::Server
|
|
||||||
attr_reader :spec_dirs
|
|
||||||
|
|
||||||
include ERB::Util
|
|
||||||
include Gem::UserInteraction
|
|
||||||
|
|
||||||
SEARCH = <<-ERB.freeze
|
|
||||||
<form class="headerSearch" name="headerSearchForm" method="get" action="/rdoc">
|
|
||||||
<div id="search" style="float:right">
|
|
||||||
<label for="q">Filter/Search</label>
|
|
||||||
<input id="q" type="text" style="width:10em" name="q">
|
|
||||||
<button type="submit" style="display:none"></button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
ERB
|
|
||||||
|
|
||||||
DOC_TEMPLATE = <<-'ERB'.freeze
|
|
||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!DOCTYPE html
|
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
||||||
<head>
|
|
||||||
<title>RubyGems Documentation Index</title>
|
|
||||||
<link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="fileHeader">
|
|
||||||
<%= SEARCH %>
|
|
||||||
<h1>RubyGems Documentation Index</h1>
|
|
||||||
</div>
|
|
||||||
<!-- banner header -->
|
|
||||||
|
|
||||||
<div id="bodyContent">
|
|
||||||
<div id="contextContent">
|
|
||||||
<div id="description">
|
|
||||||
<h1>Summary</h1>
|
|
||||||
<p>There are <%=values["gem_count"]%> gems installed:</p>
|
|
||||||
<p>
|
|
||||||
<%= values["specs"].map { |v| "<a href=\"##{u v["name"]}\">#{h v["name"]}</a>" }.join ', ' %>.
|
|
||||||
<h1>Gems</h1>
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<% values["specs"].each do |spec| %>
|
|
||||||
<dt>
|
|
||||||
<% if spec["first_name_entry"] then %>
|
|
||||||
<a name="<%=h spec["name"]%>"></a>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<b><%=h spec["name"]%> <%=h spec["version"]%></b>
|
|
||||||
|
|
||||||
<% if spec["ri_installed"] || spec["rdoc_installed"] then %>
|
|
||||||
<a href="<%=spec["doc_path"]%>">[rdoc]</a>
|
|
||||||
<% else %>
|
|
||||||
<span title="rdoc not installed">[rdoc]</span>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% if spec["homepage"] then %>
|
|
||||||
<a href="<%=uri_encode spec["homepage"]%>" title="<%=h spec["homepage"]%>">[www]</a>
|
|
||||||
<% else %>
|
|
||||||
<span title="no homepage available">[www]</span>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% if spec["has_deps"] then %>
|
|
||||||
- depends on
|
|
||||||
<%= spec["dependencies"].map { |v| "<a href=\"##{u v["name"]}\">#{h v["name"]}</a>" }.join ', ' %>.
|
|
||||||
<% end %>
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<%=spec["summary"]%>
|
|
||||||
<% if spec["executables"] then %>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<% if spec["only_one_executable"] then %>
|
|
||||||
Executable is
|
|
||||||
<% else %>
|
|
||||||
Executables are
|
|
||||||
<%end%>
|
|
||||||
|
|
||||||
<%= spec["executables"].map { |v| "<span class=\"context-item-name\">#{h v["executable"]}</span>"}.join ', ' %>.
|
|
||||||
|
|
||||||
<%end%>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
</dd>
|
|
||||||
<% end %>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="validator-badges">
|
|
||||||
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
ERB
|
|
||||||
|
|
||||||
# CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108
|
|
||||||
RDOC_CSS = <<-CSS.freeze
|
|
||||||
body {
|
|
||||||
font-family: Verdana,Arial,Helvetica,sans-serif;
|
|
||||||
font-size: 90%;
|
|
||||||
margin: 0;
|
|
||||||
margin-left: 40px;
|
|
||||||
padding: 0;
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
|
|
||||||
h1 { font-size: 150%; }
|
|
||||||
h2,h3,h4 { margin-top: 1em; }
|
|
||||||
|
|
||||||
a { background: #eef; color: #039; text-decoration: none; }
|
|
||||||
a:hover { background: #039; color: #eef; }
|
|
||||||
|
|
||||||
/* Override the base stylesheets Anchor inside a table cell */
|
|
||||||
td > a {
|
|
||||||
background: transparent;
|
|
||||||
color: #039;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* and inside a section title */
|
|
||||||
.section-title > a {
|
|
||||||
background: transparent;
|
|
||||||
color: #eee;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Structural elements =================================== */
|
|
||||||
|
|
||||||
div#index {
|
|
||||||
margin: 0;
|
|
||||||
margin-left: -40px;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
div#index a {
|
|
||||||
margin-left: 0.7em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#index .section-bar {
|
|
||||||
margin-left: 0px;
|
|
||||||
padding-left: 0.7em;
|
|
||||||
background: #ccc;
|
|
||||||
font-size: small;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
div#classHeader, div#fileHeader {
|
|
||||||
width: auto;
|
|
||||||
color: white;
|
|
||||||
padding: 0.5em 1.5em 0.5em 1.5em;
|
|
||||||
margin: 0;
|
|
||||||
margin-left: -40px;
|
|
||||||
border-bottom: 3px solid #006;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#classHeader a, div#fileHeader a {
|
|
||||||
background: inherit;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#classHeader td, div#fileHeader td {
|
|
||||||
background: inherit;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
div#fileHeader {
|
|
||||||
background: #057;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#classHeader {
|
|
||||||
background: #048;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.class-name-in-header {
|
|
||||||
font-size: 180%;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
div#bodyContent {
|
|
||||||
padding: 0 1.5em 0 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#description {
|
|
||||||
padding: 0.5em 1.5em;
|
|
||||||
background: #efefef;
|
|
||||||
border: 1px dotted #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#description h1,h2,h3,h4,h5,h6 {
|
|
||||||
color: #125;;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#validator-badges {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
div#validator-badges img { border: 0; }
|
|
||||||
|
|
||||||
div#copyright {
|
|
||||||
color: #333;
|
|
||||||
background: #efefef;
|
|
||||||
font: 0.75em sans-serif;
|
|
||||||
margin-top: 5em;
|
|
||||||
margin-bottom: 0;
|
|
||||||
padding: 0.5em 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* === Classes =================================== */
|
|
||||||
|
|
||||||
table.header-table {
|
|
||||||
color: white;
|
|
||||||
font-size: small;
|
|
||||||
}
|
|
||||||
|
|
||||||
.type-note {
|
|
||||||
font-size: small;
|
|
||||||
color: #DEDEDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xxsection-bar {
|
|
||||||
background: #eee;
|
|
||||||
color: #333;
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-bar {
|
|
||||||
color: #333;
|
|
||||||
border-bottom: 1px solid #999;
|
|
||||||
margin-left: -20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
background: #79a;
|
|
||||||
color: #eee;
|
|
||||||
padding: 3px;
|
|
||||||
margin-top: 2em;
|
|
||||||
margin-left: -30px;
|
|
||||||
border: 1px solid #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-aligned-row { vertical-align: top }
|
|
||||||
.bottom-aligned-row { vertical-align: bottom }
|
|
||||||
|
|
||||||
/* --- Context section classes ----------------------- */
|
|
||||||
|
|
||||||
.context-row { }
|
|
||||||
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
|
|
||||||
.context-item-value { font-size: small; color: #448; }
|
|
||||||
.context-item-desc { color: #333; padding-left: 2em; }
|
|
||||||
|
|
||||||
/* --- Method classes -------------------------- */
|
|
||||||
.method-detail {
|
|
||||||
background: #efefef;
|
|
||||||
padding: 0;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
border: 1px dotted #ccc;
|
|
||||||
}
|
|
||||||
.method-heading {
|
|
||||||
color: black;
|
|
||||||
background: #ccc;
|
|
||||||
border-bottom: 1px solid #666;
|
|
||||||
padding: 0.2em 0.5em 0 0.5em;
|
|
||||||
}
|
|
||||||
.method-signature { color: black; background: inherit; }
|
|
||||||
.method-name { font-weight: bold; }
|
|
||||||
.method-args { font-style: italic; }
|
|
||||||
.method-description { padding: 0 0.5em 0 0.5em; }
|
|
||||||
|
|
||||||
/* --- Source code sections -------------------- */
|
|
||||||
|
|
||||||
a.source-toggle { font-size: 90%; }
|
|
||||||
div.method-source-code {
|
|
||||||
background: #262626;
|
|
||||||
color: #ffdead;
|
|
||||||
margin: 1em;
|
|
||||||
padding: 0.5em;
|
|
||||||
border: 1px dashed #999;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
|
||||||
|
|
||||||
/* --- Ruby keyword styles --------------------- */
|
|
||||||
|
|
||||||
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
|
|
||||||
|
|
||||||
.ruby-constant { color: #7fffd4; background: transparent; }
|
|
||||||
.ruby-keyword { color: #00ffff; background: transparent; }
|
|
||||||
.ruby-ivar { color: #eedd82; background: transparent; }
|
|
||||||
.ruby-operator { color: #00ffee; background: transparent; }
|
|
||||||
.ruby-identifier { color: #ffdead; background: transparent; }
|
|
||||||
.ruby-node { color: #ffa07a; background: transparent; }
|
|
||||||
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
|
|
||||||
.ruby-regexp { color: #ffa07a; background: transparent; }
|
|
||||||
.ruby-value { color: #7fffd4; background: transparent; }
|
|
||||||
CSS
|
|
||||||
|
|
||||||
RDOC_NO_DOCUMENTATION = <<-'ERB'.freeze
|
|
||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
||||||
<head>
|
|
||||||
<title>Found documentation</title>
|
|
||||||
<link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="fileHeader">
|
|
||||||
<%= SEARCH %>
|
|
||||||
<h1>No documentation found</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="bodyContent">
|
|
||||||
<div id="contextContent">
|
|
||||||
<div id="description">
|
|
||||||
<p>No gems matched <%= h query.inspect %></p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Back to <a href="/">complete gem index</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="validator-badges">
|
|
||||||
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
ERB
|
|
||||||
|
|
||||||
RDOC_SEARCH_TEMPLATE = <<-'ERB'.freeze
|
|
||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
||||||
<head>
|
|
||||||
<title>Found documentation</title>
|
|
||||||
<link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="fileHeader">
|
|
||||||
<%= SEARCH %>
|
|
||||||
<h1>Found documentation</h1>
|
|
||||||
</div>
|
|
||||||
<!-- banner header -->
|
|
||||||
|
|
||||||
<div id="bodyContent">
|
|
||||||
<div id="contextContent">
|
|
||||||
<div id="description">
|
|
||||||
<h1>Summary</h1>
|
|
||||||
<p><%=doc_items.length%> documentation topics found.</p>
|
|
||||||
<h1>Topics</h1>
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<% doc_items.each do |doc_item| %>
|
|
||||||
<dt>
|
|
||||||
<b><%=doc_item[:name]%></b>
|
|
||||||
<a href="<%=u doc_item[:url]%>">[rdoc]</a>
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<%=h doc_item[:summary]%>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
</dd>
|
|
||||||
<% end %>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Back to <a href="/">complete gem index</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="validator-badges">
|
|
||||||
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
ERB
|
|
||||||
|
|
||||||
def self.run(options)
|
|
||||||
new(options[:gemdir], options[:port], options[:daemon],
|
|
||||||
options[:launch], options[:addresses]).run
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(gem_dirs, port, daemon, launch = nil, addresses = nil)
|
|
||||||
begin
|
|
||||||
require 'webrick'
|
|
||||||
rescue LoadError
|
|
||||||
abort "webrick is not found. You may need to `gem install webrick` to install webrick."
|
|
||||||
end
|
|
||||||
|
|
||||||
Gem::RDoc.load_rdoc
|
|
||||||
Socket.do_not_reverse_lookup = true
|
|
||||||
|
|
||||||
@gem_dirs = Array gem_dirs
|
|
||||||
@port = port
|
|
||||||
@daemon = daemon
|
|
||||||
@launch = launch
|
|
||||||
@addresses = addresses
|
|
||||||
|
|
||||||
logger = WEBrick::Log.new nil, WEBrick::BasicLog::FATAL
|
|
||||||
@server = WEBrick::HTTPServer.new :DoNotListen => true, :Logger => logger
|
|
||||||
|
|
||||||
@spec_dirs = @gem_dirs.map {|gem_dir| File.join gem_dir, 'specifications' }
|
|
||||||
@spec_dirs.reject! {|spec_dir| !File.directory? spec_dir }
|
|
||||||
|
|
||||||
reset_gems
|
|
||||||
|
|
||||||
@have_rdoc_4_plus = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_date(res)
|
|
||||||
res['date'] = @spec_dirs.map do |spec_dir|
|
|
||||||
File.stat(spec_dir).mtime
|
|
||||||
end.max
|
|
||||||
end
|
|
||||||
|
|
||||||
def uri_encode(str)
|
|
||||||
str.gsub(URI::UNSAFE) do |match|
|
|
||||||
match.each_byte.map {|c| sprintf('%%%02X', c.ord) }.join
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def doc_root(gem_name)
|
|
||||||
if have_rdoc_4_plus?
|
|
||||||
"/doc_root/#{u gem_name}/"
|
|
||||||
else
|
|
||||||
"/doc_root/#{u gem_name}/rdoc/index.html"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def have_rdoc_4_plus?
|
|
||||||
@have_rdoc_4_plus ||=
|
|
||||||
Gem::Requirement.new('>= 4.0.0.preview2').satisfied_by? Gem::RDoc.rdoc_version
|
|
||||||
end
|
|
||||||
|
|
||||||
def latest_specs(req, res)
|
|
||||||
reset_gems
|
|
||||||
|
|
||||||
res['content-type'] = 'application/x-gzip'
|
|
||||||
|
|
||||||
add_date res
|
|
||||||
|
|
||||||
latest_specs = Gem::Specification.latest_specs
|
|
||||||
|
|
||||||
specs = latest_specs.sort.map do |spec|
|
|
||||||
platform = spec.original_platform || Gem::Platform::RUBY
|
|
||||||
[spec.name, spec.version, platform]
|
|
||||||
end
|
|
||||||
|
|
||||||
specs = Marshal.dump specs
|
|
||||||
|
|
||||||
if req.path =~ /\.gz$/
|
|
||||||
specs = Gem::Util.gzip specs
|
|
||||||
res['content-type'] = 'application/x-gzip'
|
|
||||||
else
|
|
||||||
res['content-type'] = 'application/octet-stream'
|
|
||||||
end
|
|
||||||
|
|
||||||
if req.request_method == 'HEAD'
|
|
||||||
res['content-length'] = specs.length
|
|
||||||
else
|
|
||||||
res.body << specs
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Creates server sockets based on the addresses option. If no addresses
|
|
||||||
# were given a server socket for all interfaces is created.
|
|
||||||
|
|
||||||
def listen(addresses = @addresses)
|
|
||||||
addresses = [nil] unless addresses
|
|
||||||
|
|
||||||
listeners = 0
|
|
||||||
|
|
||||||
addresses.each do |address|
|
|
||||||
begin
|
|
||||||
@server.listen address, @port
|
|
||||||
@server.listeners[listeners..-1].each do |listener|
|
|
||||||
host, port = listener.addr.values_at 2, 1
|
|
||||||
host = "[#{host}]" if host =~ /:/ # we don't reverse lookup
|
|
||||||
say "Server started at http://#{host}:#{port}"
|
|
||||||
end
|
|
||||||
|
|
||||||
listeners = @server.listeners.length
|
|
||||||
rescue SystemCallError
|
|
||||||
next
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if @server.listeners.empty?
|
|
||||||
say "Unable to start a server."
|
|
||||||
say "Check for running servers or your --bind and --port arguments"
|
|
||||||
terminate_interaction 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def prerelease_specs(req, res)
|
|
||||||
reset_gems
|
|
||||||
|
|
||||||
res['content-type'] = 'application/x-gzip'
|
|
||||||
|
|
||||||
add_date res
|
|
||||||
|
|
||||||
specs = Gem::Specification.select do |spec|
|
|
||||||
spec.version.prerelease?
|
|
||||||
end.sort.map do |spec|
|
|
||||||
platform = spec.original_platform || Gem::Platform::RUBY
|
|
||||||
[spec.name, spec.version, platform]
|
|
||||||
end
|
|
||||||
|
|
||||||
specs = Marshal.dump specs
|
|
||||||
|
|
||||||
if req.path =~ /\.gz$/
|
|
||||||
specs = Gem::Util.gzip specs
|
|
||||||
res['content-type'] = 'application/x-gzip'
|
|
||||||
else
|
|
||||||
res['content-type'] = 'application/octet-stream'
|
|
||||||
end
|
|
||||||
|
|
||||||
if req.request_method == 'HEAD'
|
|
||||||
res['content-length'] = specs.length
|
|
||||||
else
|
|
||||||
res.body << specs
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def quick(req, res)
|
|
||||||
reset_gems
|
|
||||||
|
|
||||||
res['content-type'] = 'text/plain'
|
|
||||||
add_date res
|
|
||||||
|
|
||||||
case req.request_uri.path
|
|
||||||
when %r{^/quick/(Marshal.#{Regexp.escape Gem.marshal_version}/)?(.*?)\.gemspec\.rz$} then
|
|
||||||
marshal_format, full_name = $1, $2
|
|
||||||
specs = Gem::Specification.find_all_by_full_name(full_name)
|
|
||||||
|
|
||||||
selector = full_name.inspect
|
|
||||||
|
|
||||||
if specs.empty?
|
|
||||||
res.status = 404
|
|
||||||
res.body = "No gems found matching #{selector}"
|
|
||||||
elsif specs.length > 1
|
|
||||||
res.status = 500
|
|
||||||
res.body = "Multiple gems found matching #{selector}"
|
|
||||||
elsif marshal_format
|
|
||||||
res['content-type'] = 'application/x-deflate'
|
|
||||||
res.body << Gem.deflate(Marshal.dump(specs.first))
|
|
||||||
end
|
|
||||||
else
|
|
||||||
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def root(req, res)
|
|
||||||
reset_gems
|
|
||||||
|
|
||||||
add_date res
|
|
||||||
|
|
||||||
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." unless
|
|
||||||
req.path == '/'
|
|
||||||
|
|
||||||
specs = []
|
|
||||||
total_file_count = 0
|
|
||||||
|
|
||||||
Gem::Specification.each do |spec|
|
|
||||||
total_file_count += spec.files.size
|
|
||||||
deps = spec.dependencies.map do |dep|
|
|
||||||
{
|
|
||||||
"name" => dep.name,
|
|
||||||
"type" => dep.type,
|
|
||||||
"version" => dep.requirement.to_s,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
deps = deps.sort_by {|dep| [dep["name"].downcase, dep["version"]] }
|
|
||||||
deps.last["is_last"] = true unless deps.empty?
|
|
||||||
|
|
||||||
# executables
|
|
||||||
executables = spec.executables.sort.collect {|exec| {"executable" => exec} }
|
|
||||||
executables = nil if executables.empty?
|
|
||||||
executables.last["is_last"] = true if executables
|
|
||||||
|
|
||||||
# Pre-process spec homepage for safety reasons
|
|
||||||
begin
|
|
||||||
homepage_uri = URI.parse(spec.homepage)
|
|
||||||
if [URI::HTTP, URI::HTTPS].member? homepage_uri.class
|
|
||||||
homepage_uri = spec.homepage
|
|
||||||
else
|
|
||||||
homepage_uri = "."
|
|
||||||
end
|
|
||||||
rescue URI::InvalidURIError
|
|
||||||
homepage_uri = "."
|
|
||||||
end
|
|
||||||
|
|
||||||
specs << {
|
|
||||||
"authors" => spec.authors.sort.join(", "),
|
|
||||||
"date" => spec.date.to_s,
|
|
||||||
"dependencies" => deps,
|
|
||||||
"doc_path" => doc_root(spec.full_name),
|
|
||||||
"executables" => executables,
|
|
||||||
"only_one_executable" => (executables && executables.size == 1),
|
|
||||||
"full_name" => spec.full_name,
|
|
||||||
"has_deps" => !deps.empty?,
|
|
||||||
"homepage" => homepage_uri,
|
|
||||||
"name" => spec.name,
|
|
||||||
"rdoc_installed" => Gem::RDoc.new(spec).rdoc_installed?,
|
|
||||||
"ri_installed" => Gem::RDoc.new(spec).ri_installed?,
|
|
||||||
"summary" => spec.summary,
|
|
||||||
"version" => spec.version.to_s,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
specs << {
|
|
||||||
"authors" => "Chad Fowler, Rich Kilmer, Jim Weirich, Eric Hodel and others",
|
|
||||||
"dependencies" => [],
|
|
||||||
"doc_path" => doc_root("rubygems-#{Gem::VERSION}"),
|
|
||||||
"executables" => [{"executable" => 'gem', "is_last" => true}],
|
|
||||||
"only_one_executable" => true,
|
|
||||||
"full_name" => "rubygems-#{Gem::VERSION}",
|
|
||||||
"has_deps" => false,
|
|
||||||
"homepage" => "https://guides.rubygems.org/",
|
|
||||||
"name" => 'rubygems',
|
|
||||||
"ri_installed" => true,
|
|
||||||
"summary" => "RubyGems itself",
|
|
||||||
"version" => Gem::VERSION,
|
|
||||||
}
|
|
||||||
|
|
||||||
specs = specs.sort_by {|spec| [spec["name"].downcase, spec["version"]] }
|
|
||||||
specs.last["is_last"] = true
|
|
||||||
|
|
||||||
# tag all specs with first_name_entry
|
|
||||||
last_spec = nil
|
|
||||||
specs.each do |spec|
|
|
||||||
is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase)
|
|
||||||
spec["first_name_entry"] = is_first
|
|
||||||
last_spec = spec
|
|
||||||
end
|
|
||||||
|
|
||||||
# create page from template
|
|
||||||
template = ERB.new(DOC_TEMPLATE)
|
|
||||||
res['content-type'] = 'text/html'
|
|
||||||
|
|
||||||
values = { "gem_count" => specs.size.to_s, "specs" => specs,
|
|
||||||
"total_file_count" => total_file_count.to_s }
|
|
||||||
|
|
||||||
# suppress 1.9.3dev warning about unused variable
|
|
||||||
values = values
|
|
||||||
|
|
||||||
result = template.result binding
|
|
||||||
res.body = result
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Can be used for quick navigation to the rdoc documentation. You can then
|
|
||||||
# define a search shortcut for your browser. E.g. in Firefox connect
|
|
||||||
# 'shortcut:rdoc' to http://localhost:8808/rdoc?q=%s template. Then you can
|
|
||||||
# directly open the ActionPack documentation by typing 'rdoc actionp'. If
|
|
||||||
# there are multiple hits for the search term, they are presented as a list
|
|
||||||
# with links.
|
|
||||||
#
|
|
||||||
# Search algorithm aims for an intuitive search:
|
|
||||||
# 1. first try to find the gems and documentation folders which name
|
|
||||||
# starts with the search term
|
|
||||||
# 2. search for entries, that *contain* the search term
|
|
||||||
# 3. show all the gems
|
|
||||||
#
|
|
||||||
# If there is only one search hit, user is immediately redirected to the
|
|
||||||
# documentation for the particular gem, otherwise a list with results is
|
|
||||||
# shown.
|
|
||||||
#
|
|
||||||
# === Additional trick - install documentation for Ruby core
|
|
||||||
#
|
|
||||||
# Note: please adjust paths accordingly use for example 'locate yaml.rb' and
|
|
||||||
# 'gem environment' to identify directories, that are specific for your
|
|
||||||
# local installation
|
|
||||||
#
|
|
||||||
# 1. install Ruby sources
|
|
||||||
# cd /usr/src
|
|
||||||
# sudo apt-get source ruby
|
|
||||||
#
|
|
||||||
# 2. generate documentation
|
|
||||||
# rdoc -o /usr/lib/ruby/gems/1.8/doc/core/rdoc \
|
|
||||||
# /usr/lib/ruby/1.8 ruby1.8-1.8.7.72
|
|
||||||
#
|
|
||||||
# By typing 'rdoc core' you can now access the core documentation
|
|
||||||
|
|
||||||
def rdoc(req, res)
|
|
||||||
query = req.query['q']
|
|
||||||
show_rdoc_for_pattern("#{query}*", res) && return
|
|
||||||
show_rdoc_for_pattern("*#{query}*", res) && return
|
|
||||||
|
|
||||||
template = ERB.new RDOC_NO_DOCUMENTATION
|
|
||||||
|
|
||||||
res['content-type'] = 'text/html'
|
|
||||||
res.body = template.result binding
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Updates the server to use the latest installed gems.
|
|
||||||
|
|
||||||
def reset_gems # :nodoc:
|
|
||||||
Gem::Specification.dirs = @gem_dirs
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns true and prepares http response, if rdoc for the requested gem
|
|
||||||
# name pattern was found.
|
|
||||||
#
|
|
||||||
# The search is based on the file system content, not on the gems metadata.
|
|
||||||
# This allows additional documentation folders like 'core' for the Ruby core
|
|
||||||
# documentation - just put it underneath the main doc folder.
|
|
||||||
|
|
||||||
def show_rdoc_for_pattern(pattern, res)
|
|
||||||
found_gems = Dir.glob("{#{@gem_dirs.join ','}}/doc/#{pattern}").select do |path|
|
|
||||||
File.exist? File.join(path, 'rdoc/index.html')
|
|
||||||
end
|
|
||||||
case found_gems.length
|
|
||||||
when 0
|
|
||||||
return false
|
|
||||||
when 1
|
|
||||||
new_path = File.basename(found_gems[0])
|
|
||||||
res.status = 302
|
|
||||||
res['Location'] = doc_root new_path
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
doc_items = []
|
|
||||||
found_gems.each do |file_name|
|
|
||||||
base_name = File.basename(file_name)
|
|
||||||
doc_items << {
|
|
||||||
:name => base_name,
|
|
||||||
:url => doc_root(new_path),
|
|
||||||
:summary => '',
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
template = ERB.new(RDOC_SEARCH_TEMPLATE)
|
|
||||||
res['content-type'] = 'text/html'
|
|
||||||
result = template.result binding
|
|
||||||
res.body = result
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def run
|
|
||||||
listen
|
|
||||||
|
|
||||||
WEBrick::Daemon.start if @daemon
|
|
||||||
|
|
||||||
@server.mount_proc "/specs.#{Gem.marshal_version}", method(:specs)
|
|
||||||
@server.mount_proc "/specs.#{Gem.marshal_version}.gz", method(:specs)
|
|
||||||
|
|
||||||
@server.mount_proc "/latest_specs.#{Gem.marshal_version}",
|
|
||||||
method(:latest_specs)
|
|
||||||
@server.mount_proc "/latest_specs.#{Gem.marshal_version}.gz",
|
|
||||||
method(:latest_specs)
|
|
||||||
|
|
||||||
@server.mount_proc "/prerelease_specs.#{Gem.marshal_version}",
|
|
||||||
method(:prerelease_specs)
|
|
||||||
@server.mount_proc "/prerelease_specs.#{Gem.marshal_version}.gz",
|
|
||||||
method(:prerelease_specs)
|
|
||||||
|
|
||||||
@server.mount_proc "/quick/", method(:quick)
|
|
||||||
|
|
||||||
@server.mount_proc("/gem-server-rdoc-style.css") do |req, res|
|
|
||||||
res['content-type'] = 'text/css'
|
|
||||||
add_date res
|
|
||||||
res.body << RDOC_CSS
|
|
||||||
end
|
|
||||||
|
|
||||||
@server.mount_proc "/", method(:root)
|
|
||||||
|
|
||||||
@server.mount_proc "/rdoc", method(:rdoc)
|
|
||||||
|
|
||||||
file_handlers = {
|
|
||||||
'/gems' => '/cache/',
|
|
||||||
}
|
|
||||||
|
|
||||||
if have_rdoc_4_plus?
|
|
||||||
@server.mount '/doc_root', RDoc::Servlet, '/doc_root'
|
|
||||||
else
|
|
||||||
file_handlers['/doc_root'] = '/doc/'
|
|
||||||
end
|
|
||||||
|
|
||||||
@gem_dirs.each do |gem_dir|
|
|
||||||
file_handlers.each do |mount_point, mount_dir|
|
|
||||||
@server.mount(mount_point, WEBrick::HTTPServlet::FileHandler,
|
|
||||||
File.join(gem_dir, mount_dir), true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
trap("INT") { @server.shutdown; exit! }
|
|
||||||
trap("TERM") { @server.shutdown; exit! }
|
|
||||||
|
|
||||||
launch if @launch
|
|
||||||
|
|
||||||
@server.start
|
|
||||||
end
|
|
||||||
|
|
||||||
def specs(req, res)
|
|
||||||
reset_gems
|
|
||||||
|
|
||||||
add_date res
|
|
||||||
|
|
||||||
specs = Gem::Specification.sort_by(&:sort_obj).map do |spec|
|
|
||||||
platform = spec.original_platform || Gem::Platform::RUBY
|
|
||||||
[spec.name, spec.version, platform]
|
|
||||||
end
|
|
||||||
|
|
||||||
specs = Marshal.dump specs
|
|
||||||
|
|
||||||
if req.path =~ /\.gz$/
|
|
||||||
specs = Gem::Util.gzip specs
|
|
||||||
res['content-type'] = 'application/x-gzip'
|
|
||||||
else
|
|
||||||
res['content-type'] = 'application/octet-stream'
|
|
||||||
end
|
|
||||||
|
|
||||||
if req.request_method == 'HEAD'
|
|
||||||
res['content-length'] = specs.length
|
|
||||||
else
|
|
||||||
res.body << specs
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def launch
|
|
||||||
listeners = @server.listeners.map{|l| l.addr[2] }
|
|
||||||
|
|
||||||
# TODO: 0.0.0.0 == any, not localhost.
|
|
||||||
host = listeners.any?{|l| l == '0.0.0.0' } ? 'localhost' : listeners.first
|
|
||||||
|
|
||||||
say "Launching browser to http://#{host}:#{@port}"
|
|
||||||
|
|
||||||
system("#{@launch} http://#{host}:#{@port}")
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -9,53 +9,11 @@ class TestGemCommandsServerCommand < Gem::TestCase
|
||||||
@cmd = Gem::Commands::ServerCommand.new
|
@cmd = Gem::Commands::ServerCommand.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_handle_options
|
def test_execute
|
||||||
@cmd.send :handle_options, %w[-p 8808 --no-daemon]
|
use_ui @ui do
|
||||||
|
@cmd.execute
|
||||||
assert_equal false, @cmd.options[:daemon]
|
|
||||||
assert_equal [], @cmd.options[:gemdir]
|
|
||||||
assert_equal 8808, @cmd.options[:port]
|
|
||||||
|
|
||||||
@cmd.send :handle_options, %w[-p 9999 -d /nonexistent --daemon]
|
|
||||||
|
|
||||||
assert_equal true, @cmd.options[:daemon]
|
|
||||||
assert_equal [File.expand_path('/nonexistent')], @cmd.options[:gemdir]
|
|
||||||
assert_equal 9999, @cmd.options[:port]
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_handle_options_gemdir
|
|
||||||
@cmd.send :handle_options, %w[--dir a --dir b]
|
|
||||||
|
|
||||||
assert_equal [File.expand_path('a'), File.expand_path('b')],
|
|
||||||
@cmd.options[:gemdir]
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_handle_options_port
|
|
||||||
@cmd.send :handle_options, %w[-p 0]
|
|
||||||
assert_equal 0, @cmd.options[:port]
|
|
||||||
|
|
||||||
@cmd.send :handle_options, %w[-p 65535]
|
|
||||||
assert_equal 65535, @cmd.options[:port]
|
|
||||||
|
|
||||||
begin
|
|
||||||
@cmd.send :handle_options, %w[-p discard]
|
|
||||||
assert_equal 9, @cmd.options[:port]
|
|
||||||
rescue OptionParser::InvalidArgument
|
|
||||||
# for container environment on GitHub Actions
|
|
||||||
end
|
end
|
||||||
|
|
||||||
e = assert_raise OptionParser::InvalidArgument do
|
assert_match %r{Install the rubygems-server}i, @ui.error
|
||||||
@cmd.send :handle_options, %w[-p nonexistent]
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal 'invalid argument: -p nonexistent: no such named service',
|
|
||||||
e.message
|
|
||||||
|
|
||||||
e = assert_raise OptionParser::InvalidArgument do
|
|
||||||
@cmd.send :handle_options, %w[-p 65536]
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal 'invalid argument: -p 65536: not a port number',
|
|
||||||
e.message
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,608 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
require_relative 'helper'
|
|
||||||
require 'rubygems/server'
|
|
||||||
require 'stringio'
|
|
||||||
|
|
||||||
class Gem::Server
|
|
||||||
attr_reader :server
|
|
||||||
end
|
|
||||||
|
|
||||||
class TestGemServer < Gem::TestCase
|
|
||||||
def process_based_port
|
|
||||||
0
|
|
||||||
end
|
|
||||||
|
|
||||||
def setup
|
|
||||||
super
|
|
||||||
|
|
||||||
@a1 = quick_gem 'a', '1'
|
|
||||||
@a2 = quick_gem 'a', '2'
|
|
||||||
@a3_p = quick_gem 'a', '3.a'
|
|
||||||
|
|
||||||
@server = Gem::Server.new Gem.dir, process_based_port, false
|
|
||||||
@req = WEBrick::HTTPRequest.new :Logger => nil
|
|
||||||
@res = WEBrick::HTTPResponse.new :HTTPVersion => '1.0'
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_doc_root_3
|
|
||||||
orig_rdoc_version = Gem::RDoc.rdoc_version
|
|
||||||
Gem::RDoc.instance_variable_set :@rdoc_version, Gem::Version.new('3.12')
|
|
||||||
|
|
||||||
assert_equal '/doc_root/X-1/rdoc/index.html', @server.doc_root('X-1')
|
|
||||||
|
|
||||||
ensure
|
|
||||||
Gem::RDoc.instance_variable_set :@rdoc_version, orig_rdoc_version
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_doc_root_4
|
|
||||||
orig_rdoc_version = Gem::RDoc.rdoc_version
|
|
||||||
Gem::RDoc.instance_variable_set :@rdoc_version, Gem::Version.new('4.0')
|
|
||||||
|
|
||||||
assert_equal '/doc_root/X-1/', @server.doc_root('X-1')
|
|
||||||
|
|
||||||
ensure
|
|
||||||
Gem::RDoc.instance_variable_set :@rdoc_version, orig_rdoc_version
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_have_rdoc_4_plus_eh
|
|
||||||
orig_rdoc_version = Gem::RDoc.rdoc_version
|
|
||||||
Gem::RDoc.instance_variable_set(:@rdoc_version, Gem::Version.new('4.0'))
|
|
||||||
|
|
||||||
server = Gem::Server.new Gem.dir, 0, false
|
|
||||||
assert server.have_rdoc_4_plus?
|
|
||||||
|
|
||||||
Gem::RDoc.instance_variable_set :@rdoc_version, Gem::Version.new('3.12')
|
|
||||||
|
|
||||||
server = Gem::Server.new Gem.dir, 0, false
|
|
||||||
refute server.have_rdoc_4_plus?
|
|
||||||
|
|
||||||
Gem::RDoc.instance_variable_set(:@rdoc_version,
|
|
||||||
Gem::Version.new('4.0.0.preview2'))
|
|
||||||
|
|
||||||
server = Gem::Server.new Gem.dir, 0, false
|
|
||||||
assert server.have_rdoc_4_plus?
|
|
||||||
ensure
|
|
||||||
Gem::RDoc.instance_variable_set :@rdoc_version, orig_rdoc_version
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_spec_dirs
|
|
||||||
s = Gem::Server.new Gem.dir, process_based_port, false
|
|
||||||
|
|
||||||
assert_equal [File.join(Gem.dir, 'specifications')], s.spec_dirs
|
|
||||||
|
|
||||||
s = Gem::Server.new [Gem.dir, Gem.dir], process_based_port, false
|
|
||||||
|
|
||||||
assert_equal [File.join(Gem.dir, 'specifications'),
|
|
||||||
File.join(Gem.dir, 'specifications')], s.spec_dirs
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_latest_specs
|
|
||||||
data = StringIO.new "GET /latest_specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
Gem::Deprecate.skip_during do
|
|
||||||
@server.latest_specs @req, @res
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert_match %r{ \d\d:\d\d:\d\d }, @res['date']
|
|
||||||
assert_equal 'application/octet-stream', @res['content-type']
|
|
||||||
assert_equal [['a', Gem::Version.new(2), Gem::Platform::RUBY]],
|
|
||||||
Marshal.load(@res.body)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_latest_specs_gemdirs
|
|
||||||
data = StringIO.new "GET /latest_specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n"
|
|
||||||
dir = "#{@gemhome}2"
|
|
||||||
|
|
||||||
spec = util_spec 'z', 9
|
|
||||||
|
|
||||||
specs_dir = File.join dir, 'specifications'
|
|
||||||
FileUtils.mkdir_p specs_dir
|
|
||||||
|
|
||||||
File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
|
|
||||||
io.write spec.to_ruby
|
|
||||||
end
|
|
||||||
|
|
||||||
server = Gem::Server.new dir, process_based_port, false
|
|
||||||
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
server.latest_specs @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status
|
|
||||||
|
|
||||||
assert_equal [['z', v(9), Gem::Platform::RUBY]], Marshal.load(@res.body)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_latest_specs_gz
|
|
||||||
data = StringIO.new "GET /latest_specs.#{Gem.marshal_version}.gz HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
Gem::Deprecate.skip_during do
|
|
||||||
@server.latest_specs @req, @res
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert_match %r{ \d\d:\d\d:\d\d }, @res['date']
|
|
||||||
assert_equal 'application/x-gzip', @res['content-type']
|
|
||||||
assert_equal [['a', Gem::Version.new(2), Gem::Platform::RUBY]],
|
|
||||||
Marshal.load(Gem::Util.gunzip(@res.body))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_listen
|
|
||||||
util_listen
|
|
||||||
|
|
||||||
capture_output do
|
|
||||||
@server.listen
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal 1, @server.server.listeners.length
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_listen_addresses
|
|
||||||
util_listen
|
|
||||||
|
|
||||||
capture_output do
|
|
||||||
@server.listen %w[a b]
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal 2, @server.server.listeners.length
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_prerelease_specs
|
|
||||||
data = StringIO.new "GET /prerelease_specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
Gem::Deprecate.skip_during do
|
|
||||||
@server.prerelease_specs @req, @res
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert_match %r{ \d\d:\d\d:\d\d }, @res['date']
|
|
||||||
assert_equal 'application/octet-stream', @res['content-type']
|
|
||||||
assert_equal [['a', v('3.a'), Gem::Platform::RUBY]],
|
|
||||||
Marshal.load(@res.body)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_prerelease_specs_gz
|
|
||||||
data = StringIO.new "GET /prerelease_specs.#{Gem.marshal_version}.gz HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
Gem::Deprecate.skip_during do
|
|
||||||
@server.prerelease_specs @req, @res
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert_match %r{ \d\d:\d\d:\d\d }, @res['date']
|
|
||||||
assert_equal 'application/x-gzip', @res['content-type']
|
|
||||||
assert_equal [['a', v('3.a'), Gem::Platform::RUBY]],
|
|
||||||
Marshal.load(Gem::Util.gunzip(@res.body))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_quick_gemdirs
|
|
||||||
data = StringIO.new "GET /quick/Marshal.4.8/z-9.gemspec.rz HTTP/1.0\r\n\r\n"
|
|
||||||
dir = "#{@gemhome}2"
|
|
||||||
|
|
||||||
server = Gem::Server.new dir, process_based_port, false
|
|
||||||
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
server.quick @req, @res
|
|
||||||
|
|
||||||
assert_equal 404, @res.status
|
|
||||||
|
|
||||||
spec = util_spec 'z', 9
|
|
||||||
|
|
||||||
specs_dir = File.join dir, 'specifications'
|
|
||||||
|
|
||||||
FileUtils.mkdir_p specs_dir
|
|
||||||
|
|
||||||
File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
|
|
||||||
io.write spec.to_ruby
|
|
||||||
end
|
|
||||||
|
|
||||||
data.rewind
|
|
||||||
|
|
||||||
req = WEBrick::HTTPRequest.new :Logger => nil
|
|
||||||
res = WEBrick::HTTPResponse.new :HTTPVersion => '1.0'
|
|
||||||
req.parse data
|
|
||||||
|
|
||||||
server.quick req, res
|
|
||||||
|
|
||||||
assert_equal 200, res.status
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_quick_missing
|
|
||||||
data = StringIO.new "GET /quick/Marshal.4.8/z-9.gemspec.rz HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
@server.quick @req, @res
|
|
||||||
|
|
||||||
assert_equal 404, @res.status, @res.body
|
|
||||||
assert_match %r{ \d\d:\d\d:\d\d }, @res['date']
|
|
||||||
assert_equal 'text/plain', @res['content-type']
|
|
||||||
assert_equal 'No gems found matching "z-9"', @res.body
|
|
||||||
assert_equal 404, @res.status
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_quick_marshal_a_1_gemspec_rz
|
|
||||||
data = StringIO.new "GET /quick/Marshal.#{Gem.marshal_version}/a-1.gemspec.rz HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
@server.quick @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert @res['date']
|
|
||||||
assert_equal 'application/x-deflate', @res['content-type']
|
|
||||||
|
|
||||||
spec = Marshal.load Gem::Util.inflate(@res.body)
|
|
||||||
assert_equal 'a', spec.name
|
|
||||||
assert_equal Gem::Version.new(1), spec.version
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_quick_marshal_a_1_mswin32_gemspec_rz
|
|
||||||
quick_gem 'a', '1' do |s|
|
|
||||||
s.platform = Gem::Platform.local
|
|
||||||
end
|
|
||||||
|
|
||||||
data = StringIO.new "GET /quick/Marshal.#{Gem.marshal_version}/a-1-#{Gem::Platform.local}.gemspec.rz HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
@server.quick @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert @res['date']
|
|
||||||
assert_equal 'application/x-deflate', @res['content-type']
|
|
||||||
|
|
||||||
spec = Marshal.load Gem::Util.inflate(@res.body)
|
|
||||||
assert_equal 'a', spec.name
|
|
||||||
assert_equal Gem::Version.new(1), spec.version
|
|
||||||
assert_equal Gem::Platform.local, spec.platform
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_quick_marshal_a_3_a_gemspec_rz
|
|
||||||
data = StringIO.new "GET /quick/Marshal.#{Gem.marshal_version}/a-3.a.gemspec.rz HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
@server.quick @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert @res['date']
|
|
||||||
assert_equal 'application/x-deflate', @res['content-type']
|
|
||||||
|
|
||||||
spec = Marshal.load Gem::Util.inflate(@res.body)
|
|
||||||
assert_equal 'a', spec.name
|
|
||||||
assert_equal v('3.a'), spec.version
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_quick_marshal_a_b_3_a_gemspec_rz
|
|
||||||
quick_gem 'a-b', '3.a'
|
|
||||||
|
|
||||||
data = StringIO.new "GET /quick/Marshal.#{Gem.marshal_version}/a-b-3.a.gemspec.rz HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
@server.quick @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert @res['date']
|
|
||||||
assert_equal 'application/x-deflate', @res['content-type']
|
|
||||||
|
|
||||||
spec = Marshal.load Gem::Util.inflate(@res.body)
|
|
||||||
assert_equal 'a-b', spec.name
|
|
||||||
assert_equal v('3.a'), spec.version
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_quick_marshal_a_b_1_3_a_gemspec_rz
|
|
||||||
quick_gem 'a-b-1', '3.a'
|
|
||||||
|
|
||||||
data = StringIO.new "GET /quick/Marshal.#{Gem.marshal_version}/a-b-1-3.a.gemspec.rz HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
@server.quick @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert @res['date']
|
|
||||||
assert_equal 'application/x-deflate', @res['content-type']
|
|
||||||
|
|
||||||
spec = Marshal.load Gem::Util.inflate(@res.body)
|
|
||||||
assert_equal 'a-b-1', spec.name
|
|
||||||
assert_equal v('3.a'), spec.version
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_rdoc
|
|
||||||
data = StringIO.new "GET /rdoc?q=a HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
@server.rdoc @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert_match %r{No documentation found}, @res.body
|
|
||||||
assert_equal 'text/html', @res['content-type']
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_root
|
|
||||||
data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
@server.root @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert_match %r{ \d\d:\d\d:\d\d }, @res['date']
|
|
||||||
assert_equal 'text/html', @res['content-type']
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_root_gemdirs
|
|
||||||
data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
|
|
||||||
dir = "#{@gemhome}2"
|
|
||||||
|
|
||||||
spec = util_spec 'z', 9
|
|
||||||
|
|
||||||
specs_dir = File.join dir, 'specifications'
|
|
||||||
FileUtils.mkdir_p specs_dir
|
|
||||||
|
|
||||||
File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
|
|
||||||
io.write spec.to_ruby
|
|
||||||
end
|
|
||||||
|
|
||||||
server = Gem::Server.new dir, process_based_port, false
|
|
||||||
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
server.root @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status
|
|
||||||
assert_match 'z 9', @res.body
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_xss_homepage_fix_289313
|
|
||||||
data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
|
|
||||||
dir = "#{@gemhome}2"
|
|
||||||
|
|
||||||
spec = util_spec 'xsshomepagegem', 1
|
|
||||||
spec.homepage = "javascript:confirm(document.domain)"
|
|
||||||
|
|
||||||
specs_dir = File.join dir, 'specifications'
|
|
||||||
FileUtils.mkdir_p specs_dir
|
|
||||||
|
|
||||||
File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
|
|
||||||
io.write spec.to_ruby
|
|
||||||
end
|
|
||||||
|
|
||||||
server = Gem::Server.new dir, process_based_port, false
|
|
||||||
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
server.root @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status
|
|
||||||
assert_match 'xsshomepagegem 1', @res.body
|
|
||||||
|
|
||||||
# This verifies that the homepage for this spec is not displayed and is set to ".", because it's not a
|
|
||||||
# valid HTTP/HTTPS URL and could be unsafe in an HTML context. We would prefer to throw an exception here,
|
|
||||||
# but spec.homepage is currently free form and not currently required to be a URL, this behavior may be
|
|
||||||
# validated in future versions of Gem::Specification.
|
|
||||||
#
|
|
||||||
# There are two variant we're checking here, one where rdoc is not present, and one where rdoc is present in the same regex:
|
|
||||||
#
|
|
||||||
# Variant #1 - rdoc not installed
|
|
||||||
#
|
|
||||||
# <b>xsshomepagegem 1</b>
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# <span title="rdoc not installed">[rdoc]</span>
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# <a href="." title=".">[www]</a>
|
|
||||||
#
|
|
||||||
# Variant #2 - rdoc installed
|
|
||||||
#
|
|
||||||
# <b>xsshomepagegem 1</b>
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# <a href="\/doc_root\/xsshomepagegem-1\/">\[rdoc\]<\/a>
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# <a href="." title=".">[www]</a>
|
|
||||||
regex_match = /xsshomepagegem 1<\/b>\s+(<span title="rdoc not installed">\[rdoc\]<\/span>|<a href="\/doc_root\/xsshomepagegem-1\/">\[rdoc\]<\/a>)\s+<a href="\." title="\.">\[www\]<\/a>/
|
|
||||||
assert_match regex_match, @res.body
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_invalid_homepage
|
|
||||||
data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
|
|
||||||
dir = "#{@gemhome}2"
|
|
||||||
|
|
||||||
spec = util_spec 'invalidhomepagegem', 1
|
|
||||||
spec.homepage = "notavalidhomepageurl"
|
|
||||||
|
|
||||||
specs_dir = File.join dir, 'specifications'
|
|
||||||
FileUtils.mkdir_p specs_dir
|
|
||||||
|
|
||||||
File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
|
|
||||||
io.write spec.to_ruby
|
|
||||||
end
|
|
||||||
|
|
||||||
server = Gem::Server.new dir, process_based_port, false
|
|
||||||
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
server.root @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status
|
|
||||||
assert_match 'invalidhomepagegem 1', @res.body
|
|
||||||
|
|
||||||
# This verifies that the homepage for this spec is not displayed and is set to ".", because it's not a
|
|
||||||
# valid HTTP/HTTPS URL and could be unsafe in an HTML context. We would prefer to throw an exception here,
|
|
||||||
# but spec.homepage is currently free form and not currently required to be a URL, this behavior may be
|
|
||||||
# validated in future versions of Gem::Specification.
|
|
||||||
#
|
|
||||||
# There are two variant we're checking here, one where rdoc is not present, and one where rdoc is present in the same regex:
|
|
||||||
#
|
|
||||||
# Variant #1 - rdoc not installed
|
|
||||||
#
|
|
||||||
# <b>invalidhomepagegem 1</b>
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# <span title="rdoc not installed">[rdoc]</span>
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# <a href="." title=".">[www]</a>
|
|
||||||
#
|
|
||||||
# Variant #2 - rdoc installed
|
|
||||||
#
|
|
||||||
# <b>invalidhomepagegem 1</b>
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# <a href="\/doc_root\/invalidhomepagegem-1\/">\[rdoc\]<\/a>
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# <a href="." title=".">[www]</a>
|
|
||||||
regex_match = /invalidhomepagegem 1<\/b>\s+(<span title="rdoc not installed">\[rdoc\]<\/span>|<a href="\/doc_root\/invalidhomepagegem-1\/">\[rdoc\]<\/a>)\s+<a href="\." title="\.">\[www\]<\/a>/
|
|
||||||
assert_match regex_match, @res.body
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_valid_homepage_http
|
|
||||||
data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
|
|
||||||
dir = "#{@gemhome}2"
|
|
||||||
|
|
||||||
spec = util_spec 'validhomepagegemhttp', 1
|
|
||||||
spec.homepage = "http://rubygems.org"
|
|
||||||
|
|
||||||
specs_dir = File.join dir, 'specifications'
|
|
||||||
FileUtils.mkdir_p specs_dir
|
|
||||||
|
|
||||||
File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
|
|
||||||
io.write spec.to_ruby
|
|
||||||
end
|
|
||||||
|
|
||||||
server = Gem::Server.new dir, process_based_port, false
|
|
||||||
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
server.root @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status
|
|
||||||
assert_match 'validhomepagegemhttp 1', @res.body
|
|
||||||
|
|
||||||
regex_match = /validhomepagegemhttp 1<\/b>\s+(<span title="rdoc not installed">\[rdoc\]<\/span>|<a href="\/doc_root\/validhomepagegemhttp-1\/">\[rdoc\]<\/a>)\s+<a href="http:\/\/rubygems\.org" title="http:\/\/rubygems\.org">\[www\]<\/a>/
|
|
||||||
assert_match regex_match, @res.body
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_valid_homepage_https
|
|
||||||
data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
|
|
||||||
dir = "#{@gemhome}2"
|
|
||||||
|
|
||||||
spec = util_spec 'validhomepagegemhttps', 1
|
|
||||||
spec.homepage = "https://rubygems.org"
|
|
||||||
|
|
||||||
specs_dir = File.join dir, 'specifications'
|
|
||||||
FileUtils.mkdir_p specs_dir
|
|
||||||
|
|
||||||
File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
|
|
||||||
io.write spec.to_ruby
|
|
||||||
end
|
|
||||||
|
|
||||||
server = Gem::Server.new dir, process_based_port, false
|
|
||||||
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
server.root @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status
|
|
||||||
assert_match 'validhomepagegemhttps 1', @res.body
|
|
||||||
|
|
||||||
regex_match = /validhomepagegemhttps 1<\/b>\s+(<span title="rdoc not installed">\[rdoc\]<\/span>|<a href="\/doc_root\/validhomepagegemhttps-1\/">\[rdoc\]<\/a>)\s+<a href="https:\/\/rubygems\.org" title="https:\/\/rubygems\.org">\[www\]<\/a>/
|
|
||||||
assert_match regex_match, @res.body
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_specs
|
|
||||||
data = StringIO.new "GET /specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
@server.specs @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert_match %r{ \d\d:\d\d:\d\d }, @res['date']
|
|
||||||
assert_equal 'application/octet-stream', @res['content-type']
|
|
||||||
|
|
||||||
assert_equal [['a', Gem::Version.new(1), Gem::Platform::RUBY],
|
|
||||||
['a', Gem::Version.new(2), Gem::Platform::RUBY],
|
|
||||||
['a', v('3.a'), Gem::Platform::RUBY]],
|
|
||||||
Marshal.load(@res.body)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_specs_gemdirs
|
|
||||||
data = StringIO.new "GET /specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n"
|
|
||||||
dir = "#{@gemhome}2"
|
|
||||||
|
|
||||||
spec = util_spec 'z', 9
|
|
||||||
|
|
||||||
specs_dir = File.join dir, 'specifications'
|
|
||||||
FileUtils.mkdir_p specs_dir
|
|
||||||
|
|
||||||
File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
|
|
||||||
io.write spec.to_ruby
|
|
||||||
end
|
|
||||||
|
|
||||||
server = Gem::Server.new dir, process_based_port, false
|
|
||||||
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
server.specs @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status
|
|
||||||
|
|
||||||
assert_equal [['z', v(9), Gem::Platform::RUBY]], Marshal.load(@res.body)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_specs_gz
|
|
||||||
data = StringIO.new "GET /specs.#{Gem.marshal_version}.gz HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
@server.specs @req, @res
|
|
||||||
|
|
||||||
assert_equal 200, @res.status, @res.body
|
|
||||||
assert_match %r{ \d\d:\d\d:\d\d }, @res['date']
|
|
||||||
assert_equal 'application/x-gzip', @res['content-type']
|
|
||||||
|
|
||||||
assert_equal [['a', Gem::Version.new(1), Gem::Platform::RUBY],
|
|
||||||
['a', Gem::Version.new(2), Gem::Platform::RUBY],
|
|
||||||
['a', v('3.a'), Gem::Platform::RUBY]],
|
|
||||||
Marshal.load(Gem::Util.gunzip(@res.body))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_uri_encode
|
|
||||||
url_safe = @server.uri_encode 'http://rubyonrails.org/">malicious_content</a>'
|
|
||||||
assert_equal url_safe, 'http://rubyonrails.org/%22%3Emalicious_content%3C/a%3E'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Regression test for issue #1793: incorrect URL encoding.
|
|
||||||
# Checking that no URLs have had '://' incorrectly encoded
|
|
||||||
def test_regression_1793
|
|
||||||
data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
|
|
||||||
@req.parse data
|
|
||||||
|
|
||||||
@server.root @req, @res
|
|
||||||
|
|
||||||
refute_match %r{%3A%2F%2F}, @res.body
|
|
||||||
end
|
|
||||||
|
|
||||||
def util_listen
|
|
||||||
webrick = Object.new
|
|
||||||
webrick.instance_variable_set :@listeners, []
|
|
||||||
def webrick.listeners() @listeners end
|
|
||||||
def webrick.listen(host, port)
|
|
||||||
socket = Object.new
|
|
||||||
socket.instance_variable_set :@host, host
|
|
||||||
socket.instance_variable_set :@port, port
|
|
||||||
def socket.addr() [nil, @port, @host] end
|
|
||||||
@listeners << socket
|
|
||||||
end
|
|
||||||
|
|
||||||
@server.instance_variable_set :@server, webrick
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in a new issue