Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit 3764fc9

Browse files
committed
add appengine files + nodejs dev server
1 parent a82abe2 commit 3764fc9

File tree

5 files changed

+314
-0
lines changed

5 files changed

+314
-0
lines changed

app.yaml

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
application: builtwithangularjs
2+
version: 1
3+
runtime: python27
4+
api_version: 1
5+
threadsafe: yes
6+
7+
handlers:
8+
- url: /favicon\.ico
9+
static_files: favicon.ico
10+
upload: favicon\.ico
11+
12+
- url: /
13+
static_files: index.html
14+
upload: index.html
15+
16+
- url: /projects
17+
static_dir: projects
18+
19+
- url: /css
20+
static_dir: css
21+
22+
- url: /font
23+
static_dir: font
24+
25+
- url: /img
26+
static_dir: img
27+
28+
- url: /js
29+
static_dir: js
30+
31+
libraries:
32+
- name: webapp2
33+
version: "2.5.1"
34+
35+

index.yaml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
indexes:
2+
3+
# AUTOGENERATED
4+
5+
# This index.yaml is automatically updated whenever the dev_appserver
6+
# detects that a new type of query is run. If you want to manage the
7+
# index.yaml file manually, remove the above marker line (the line
8+
# saying "# AUTOGENERATED"). If you want to manage some indexes
9+
# manually, move them above the marker line. The index.yaml file is
10+
# automatically uploaded to the admin console when you next deploy
11+
# your application using appcfg.py.
12+

main.py

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env python
2+
#
3+
# Copyright 2007 Google Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
import webapp2
18+
19+
class MainHandler(webapp2.RequestHandler):
20+
def get(self):
21+
self.response.out.write('Hello world!')
22+
23+
app = webapp2.WSGIApplication([('/', MainHandler)],
24+
debug=True)

main.pyc

735 Bytes
Binary file not shown.

web-server.js

+243
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
#!/usr/bin/env node
2+
3+
var sys = require('sys'),
4+
http = require('http'),
5+
fs = require('fs'),
6+
url = require('url'),
7+
events = require('events');
8+
9+
var DEFAULT_PORT = 8000;
10+
11+
function main(argv) {
12+
new HttpServer({
13+
'GET': createServlet(StaticServlet),
14+
'HEAD': createServlet(StaticServlet)
15+
}).start(Number(argv[2]) || DEFAULT_PORT);
16+
}
17+
18+
function escapeHtml(value) {
19+
return value.toString().
20+
replace('<', '&lt;').
21+
replace('>', '&gt;').
22+
replace('"', '&quot;');
23+
}
24+
25+
function createServlet(Class) {
26+
var servlet = new Class();
27+
return servlet.handleRequest.bind(servlet);
28+
}
29+
30+
/**
31+
* An Http server implementation that uses a map of methods to decide
32+
* action routing.
33+
*
34+
* @param {Object} Map of method => Handler function
35+
*/
36+
function HttpServer(handlers) {
37+
this.handlers = handlers;
38+
this.server = http.createServer(this.handleRequest_.bind(this));
39+
}
40+
41+
HttpServer.prototype.start = function(port) {
42+
this.port = port;
43+
this.server.listen(port);
44+
sys.puts('Http Server running at http://localhost:' + port + '/');
45+
};
46+
47+
HttpServer.prototype.parseUrl_ = function(urlString) {
48+
var parsed = url.parse(urlString);
49+
parsed.pathname = url.resolve('/', parsed.pathname);
50+
return url.parse(url.format(parsed), true);
51+
};
52+
53+
HttpServer.prototype.handleRequest_ = function(req, res) {
54+
var logEntry = req.method + ' ' + req.url;
55+
if (req.headers['user-agent']) {
56+
logEntry += ' ' + req.headers['user-agent'];
57+
}
58+
sys.puts(logEntry);
59+
req.url = this.parseUrl_(req.url);
60+
var handler = this.handlers[req.method];
61+
if (!handler) {
62+
res.writeHead(501);
63+
res.end();
64+
} else {
65+
handler.call(this, req, res);
66+
}
67+
};
68+
69+
/**
70+
* Handles static content.
71+
*/
72+
function StaticServlet() {}
73+
74+
StaticServlet.MimeMap = {
75+
'txt': 'text/plain',
76+
'html': 'text/html',
77+
'css': 'text/css',
78+
'xml': 'application/xml',
79+
'json': 'application/json',
80+
'js': 'application/javascript',
81+
'jpg': 'image/jpeg',
82+
'jpeg': 'image/jpeg',
83+
'gif': 'image/gif',
84+
'png': 'image/png'
85+
};
86+
87+
StaticServlet.prototype.handleRequest = function(req, res) {
88+
var self = this;
89+
var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/, function(match, hex){
90+
return String.fromCharCode(parseInt(hex, 16));
91+
});
92+
var parts = path.split('/');
93+
if (parts[parts.length-1].charAt(0) === '.')
94+
return self.sendForbidden_(req, res, path);
95+
fs.stat(path, function(err, stat) {
96+
if (err)
97+
return self.sendMissing_(req, res, path);
98+
if (stat.isDirectory())
99+
return self.sendDirectory_(req, res, path);
100+
return self.sendFile_(req, res, path);
101+
});
102+
}
103+
104+
StaticServlet.prototype.sendError_ = function(req, res, error) {
105+
res.writeHead(500, {
106+
'Content-Type': 'text/html'
107+
});
108+
res.write('<!doctype html>\n');
109+
res.write('<title>Internal Server Error</title>\n');
110+
res.write('<h1>Internal Server Error</h1>');
111+
res.write('<pre>' + escapeHtml(sys.inspect(error)) + '</pre>');
112+
sys.puts('500 Internal Server Error');
113+
sys.puts(sys.inspect(error));
114+
};
115+
116+
StaticServlet.prototype.sendMissing_ = function(req, res, path) {
117+
path = path.substring(1);
118+
res.writeHead(404, {
119+
'Content-Type': 'text/html'
120+
});
121+
res.write('<!doctype html>\n');
122+
res.write('<title>404 Not Found</title>\n');
123+
res.write('<h1>Not Found</h1>');
124+
res.write(
125+
'<p>The requested URL ' +
126+
escapeHtml(path) +
127+
' was not found on this server.</p>'
128+
);
129+
res.end();
130+
sys.puts('404 Not Found: ' + path);
131+
};
132+
133+
StaticServlet.prototype.sendForbidden_ = function(req, res, path) {
134+
path = path.substring(1);
135+
res.writeHead(403, {
136+
'Content-Type': 'text/html'
137+
});
138+
res.write('<!doctype html>\n');
139+
res.write('<title>403 Forbidden</title>\n');
140+
res.write('<h1>Forbidden</h1>');
141+
res.write(
142+
'<p>You do not have permission to access ' +
143+
escapeHtml(path) + ' on this server.</p>'
144+
);
145+
res.end();
146+
sys.puts('403 Forbidden: ' + path);
147+
};
148+
149+
StaticServlet.prototype.sendRedirect_ = function(req, res, redirectUrl) {
150+
res.writeHead(301, {
151+
'Content-Type': 'text/html',
152+
'Location': redirectUrl
153+
});
154+
res.write('<!doctype html>\n');
155+
res.write('<title>301 Moved Permanently</title>\n');
156+
res.write('<h1>Moved Permanently</h1>');
157+
res.write(
158+
'<p>The document has moved <a href="' +
159+
redirectUrl +
160+
'">here</a>.</p>'
161+
);
162+
res.end();
163+
sys.puts('301 Moved Permanently: ' + redirectUrl);
164+
};
165+
166+
StaticServlet.prototype.sendFile_ = function(req, res, path) {
167+
var self = this;
168+
var file = fs.createReadStream(path);
169+
res.writeHead(200, {
170+
'Content-Type': StaticServlet.
171+
MimeMap[path.split('.').pop()] || 'text/plain'
172+
});
173+
if (req.method === 'HEAD') {
174+
res.end();
175+
} else {
176+
file.on('data', res.write.bind(res));
177+
file.on('close', function() {
178+
res.end();
179+
});
180+
file.on('error', function(error) {
181+
self.sendError_(req, res, error);
182+
});
183+
}
184+
};
185+
186+
StaticServlet.prototype.sendDirectory_ = function(req, res, path) {
187+
var self = this;
188+
if (path.match(/[^\/]$/)) {
189+
req.url.pathname += '/';
190+
var redirectUrl = url.format(url.parse(url.format(req.url)));
191+
return self.sendRedirect_(req, res, redirectUrl);
192+
}
193+
fs.readdir(path, function(err, files) {
194+
if (err)
195+
return self.sendError_(req, res, error);
196+
197+
if (!files.length)
198+
return self.writeDirectoryIndex_(req, res, path, []);
199+
200+
var remaining = files.length;
201+
files.forEach(function(fileName, index) {
202+
fs.stat(path + '/' + fileName, function(err, stat) {
203+
if (err)
204+
return self.sendError_(req, res, err);
205+
if (stat.isDirectory()) {
206+
files[index] = fileName + '/';
207+
}
208+
if (!(--remaining))
209+
return self.writeDirectoryIndex_(req, res, path, files);
210+
});
211+
});
212+
});
213+
};
214+
215+
StaticServlet.prototype.writeDirectoryIndex_ = function(req, res, path, files) {
216+
path = path.substring(1);
217+
res.writeHead(200, {
218+
'Content-Type': 'text/html'
219+
});
220+
if (req.method === 'HEAD') {
221+
res.end();
222+
return;
223+
}
224+
res.write('<!doctype html>\n');
225+
res.write('<title>' + escapeHtml(path) + '</title>\n');
226+
res.write('<style>\n');
227+
res.write(' ol { list-style-type: none; font-size: 1.2em; }\n');
228+
res.write('</style>\n');
229+
res.write('<h1>Directory: ' + escapeHtml(path) + '</h1>');
230+
res.write('<ol>');
231+
files.forEach(function(fileName) {
232+
if (fileName.charAt(0) !== '.') {
233+
res.write('<li><a href="' +
234+
escapeHtml(fileName) + '">' +
235+
escapeHtml(fileName) + '</a></li>');
236+
}
237+
});
238+
res.write('</ol>');
239+
res.end();
240+
};
241+
242+
// Must be last,
243+
main(process.argv);

0 commit comments

Comments
 (0)