Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handling http methods #748

Merged
merged 2 commits into from
Jan 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 57 additions & 42 deletions server/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { resolve, join } from 'path'
import { parse } from 'url'
import fs from 'mz/fs'
import http from 'http'
import http, { STATUS_CODES } from 'http'
import {
renderToHTML,
renderErrorToHTML,
Expand Down Expand Up @@ -38,7 +38,7 @@ export default class Server {
.catch((err) => {
if (!this.quiet) console.error(err)
res.statusCode = 500
res.end('error')
res.end(STATUS_CODES[500])
})
}
}
Expand Down Expand Up @@ -67,43 +67,52 @@ export default class Server {
}

defineRoutes () {
this.router.get('/_next-prefetcher.js', async (req, res, params) => {
const p = join(__dirname, '../client/next-prefetcher-bundle.js')
await serveStatic(req, res, p)
})

this.router.get('/_next/:buildId/main.js', async (req, res, params) => {
this.handleBuildId(params.buildId, res)
const p = join(this.dir, '.next/main.js')
await serveStaticWithGzip(req, res, p)
})

this.router.get('/_next/:buildId/commons.js', async (req, res, params) => {
this.handleBuildId(params.buildId, res)
const p = join(this.dir, '.next/commons.js')
await serveStaticWithGzip(req, res, p)
})

this.router.get('/_next/:buildId/pages/:path*', async (req, res, params) => {
this.handleBuildId(params.buildId, res)
const paths = params.path || ['index']
const pathname = `/${paths.join('/')}`
await this.renderJSON(req, res, pathname)
})

this.router.get('/_next/:path+', async (req, res, params) => {
const p = join(__dirname, '..', 'client', ...(params.path || []))
await serveStatic(req, res, p)
})
this.router.get('/static/:path+', async (req, res, params) => {
const p = join(this.dir, 'static', ...(params.path || []))
await serveStatic(req, res, p)
})
const routes = {
'/_next-prefetcher.js': async (req, res, params) => {
const p = join(__dirname, '../client/next-prefetcher-bundle.js')
await this.serveStatic(req, res, p)
},

'/_next/:buildId/main.js': async (req, res, params) => {
this.handleBuildId(params.buildId, res)
const p = join(this.dir, '.next/main.js')
await this.serveStaticWithGzip(req, res, p)
},

'/_next/:buildId/commons.js': async (req, res, params) => {
this.handleBuildId(params.buildId, res)
const p = join(this.dir, '.next/commons.js')
await this.serveStaticWithGzip(req, res, p)
},

'/_next/:buildId/pages/:path*': async (req, res, params) => {
this.handleBuildId(params.buildId, res)
const paths = params.path || ['index']
const pathname = `/${paths.join('/')}`
await this.renderJSON(req, res, pathname)
},

'/_next/:path+': async (req, res, params) => {
const p = join(__dirname, '..', 'client', ...(params.path || []))
await this.serveStatic(req, res, p)
},

'/static/:path+': async (req, res, params) => {
const p = join(this.dir, 'static', ...(params.path || []))
await this.serveStatic(req, res, p)
},

'/:path*': async (req, res) => {
const { pathname, query } = parse(req.url, true)
await this.render(req, res, pathname, query)
}
}

this.router.get('/:path*', async (req, res) => {
const { pathname, query } = parse(req.url, true)
await this.render(req, res, pathname, query)
})
for (const method of ['GET', 'HEAD']) {
for (const p of Object.keys(routes)) {
this.router.add(method, p, routes[p])
}
}
}

async start (port) {
Expand All @@ -125,8 +134,14 @@ export default class Server {
const fn = this.router.match(req, res)
if (fn) {
await fn()
} else {
return
}

if (req.method === 'GET' || req.method === 'HEAD') {
await this.render404(req, res)
} else {
res.statusCode = 501
res.end(STATUS_CODES[501])
}
}

Expand All @@ -135,7 +150,7 @@ export default class Server {
res.setHeader('X-Powered-By', `Next.js ${pkg.version}`)
}
const html = await this.renderToHTML(req, res, pathname, query)
sendHTML(res, html)
sendHTML(res, html, req.method)
}

async renderToHTML (req, res, pathname, query) {
Expand Down Expand Up @@ -163,7 +178,7 @@ export default class Server {

async renderError (err, req, res, pathname, query) {
const html = await this.renderErrorToHTML(err, req, res, pathname, query)
sendHTML(res, html)
sendHTML(res, html, req.method)
}

async renderErrorToHTML (err, req, res, pathname, query) {
Expand Down Expand Up @@ -191,7 +206,7 @@ export default class Server {
async render404 (req, res) {
const { pathname, query } = parse(req.url, true)
res.statusCode = 404
this.renderErrorToHTML(null, req, res, pathname, query)
this.renderError(null, req, res, pathname, query)
}

async renderJSON (req, res, page) {
Expand Down
14 changes: 7 additions & 7 deletions server/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import App from '../lib/app'

export async function render (req, res, pathname, query, opts) {
const html = await renderToHTML(req, res, pathname, opts)
sendHTML(res, html)
sendHTML(res, html, req.method)
}

export function renderToHTML (req, res, pathname, query, opts) {
Expand All @@ -23,7 +23,7 @@ export function renderToHTML (req, res, pathname, query, opts) {

export async function renderError (err, req, res, pathname, query, opts) {
const html = await renderErrorToHTML(err, req, res, query, opts)
sendHTML(res, html)
sendHTML(res, html, req.method)
}

export function renderErrorToHTML (err, req, res, pathname, query, opts = {}) {
Expand Down Expand Up @@ -111,24 +111,24 @@ export async function renderErrorJSON (err, req, res, { dir = process.cwd(), dev
sendJSON(res, {
component,
err: err && dev ? errorToJSON(err) : null
})
}, req.method)
}

export function sendHTML (res, html) {
export function sendHTML (res, html, method) {
if (res.finished) return

res.setHeader('Content-Type', 'text/html')
res.setHeader('Content-Length', Buffer.byteLength(html))
res.end(html)
res.end(method === 'HEAD' ? null : html)
}

export function sendJSON (res, obj) {
export function sendJSON (res, obj, method) {
if (res.finished) return

const json = JSON.stringify(obj)
res.setHeader('Content-Type', 'application/json')
res.setHeader('Content-Length', Buffer.byteLength(json))
res.end(json)
res.end(method === 'HEAD' ? null : json)
}

function errorToJSON (err) {
Expand Down
4 changes: 0 additions & 4 deletions server/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ export default class Router {
this.routes = new Map()
}

get (path, fn) {
this.add('GET', path, fn)
}

add (method, path, fn) {
const routes = this.routes.get(method) || new Set()
routes.add({ match: route(path), fn })
Expand Down