@Override public @Nullable FullHttpResponse handleRequest(ChannelHandlerContext ctx, HttpRequest request) throws Exception { QueryStringDecoder decoder = new QueryStringDecoder(request.uri()); List<String> agentIds = decoder.parameters().get("agent-id"); if (agentIds == null) { agentIds = ImmutableList.of(""); } String agentId = agentIds.get(0); List<String> traceIds = decoder.parameters().get("trace-id"); checkNotNull(traceIds, "Missing trace id in query string: %s", request.uri()); String traceId = traceIds.get(0); // check-live-traces is an optimization so glowroot server only has to check with remote // agents when necessary List<String> checkLiveTracesParams = decoder.parameters().get("check-live-traces"); boolean checkLiveTraces = false; if (checkLiveTracesParams != null && !checkLiveTracesParams.isEmpty()) { checkLiveTraces = Boolean.parseBoolean(checkLiveTracesParams.get(0)); } logger.debug( "handleRequest(): agentId={}, traceId={}, checkLiveTraces={}", agentId, traceId, checkLiveTraces); TraceExport traceExport = traceCommonService.getExport(agentId, traceId, checkLiveTraces); if (traceExport == null) { logger.warn("no trace found for id: {}", traceId); return new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND); } ChunkedInput<HttpContent> in = getExportChunkedInput(traceExport); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); response.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); response.headers().set(HttpHeaderNames.CONTENT_TYPE, MediaType.ZIP.toString()); response .headers() .set("Content-Disposition", "attachment; filename=" + traceExport.fileName() + ".zip"); boolean keepAlive = HttpUtil.isKeepAlive(request); if (keepAlive && !request.protocolVersion().isKeepAliveDefault()) { response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); } HttpServices.preventCaching(response); ctx.write(response); ChannelFuture future = ctx.write(in); HttpServices.addErrorListener(future); if (!keepAlive) { HttpServices.addCloseListener(future); } // return null to indicate streaming return null; }
private void writeResponse(Channel channel) { // Convert the response content to a ChannelBuffer. ByteBuf buf = copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8); responseContent.setLength(0); // Decide whether to close the connection or not. boolean close = request.headers().contains(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE, true) || request.protocolVersion().equals(HttpVersion.HTTP_1_0) && !request .headers() .contains(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE, true); // Build the response object. FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf); response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8"); if (!close) { // There's no need to add 'Content-Length' header // if this is the last response. response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes()); } Set<Cookie> cookies; String value = request.headers().getAndConvert(HttpHeaderNames.COOKIE); if (value == null) { cookies = Collections.emptySet(); } else { cookies = ServerCookieDecoder.STRICT.decode(value); } if (!cookies.isEmpty()) { // Reset the cookies if necessary. for (Cookie cookie : cookies) { response .headers() .add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode(cookie)); } } // Write the response. ChannelFuture future = channel.writeAndFlush(response); // Close the connection after the write operation is done if necessary. if (close) { future.addListener(ChannelFutureListener.CLOSE); } }
@Override public @Nullable FullHttpResponse handleRequest(ChannelHandlerContext ctx, HttpRequest request) throws Exception { File glowrootLogFile = new File(logDir, "glowroot.log"); CharSource glowrootLogCharSource = Files.asCharSource(glowrootLogFile, Charsets.UTF_8); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); response.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8"); boolean keepAlive = HttpUtil.isKeepAlive(request); if (keepAlive && !request.protocolVersion().isKeepAliveDefault()) { response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); } HttpServices.preventCaching(response); ctx.write(response); ChannelFuture future = ctx.write(ChunkedInputs.from(ChunkSource.from(glowrootLogCharSource))); HttpServices.addErrorListener(future); if (!keepAlive) { HttpServices.addCloseListener(future); } // return null to indicate streaming return null; }
@Override protected void encodeInitialLine(final ByteBuf buf, final HttpMessage message) throws Exception { if (message instanceof HttpRequest) { HttpRequest request = (HttpRequest) message; ByteBufUtil.writeAscii(buf, request.method().asciiName()); buf.writeByte(SP); buf.writeBytes(request.uri().getBytes(CharsetUtil.UTF_8)); buf.writeByte(SP); ByteBufUtil.writeAscii(buf, request.protocolVersion().text()); buf.writeBytes(CRLF); } else if (message instanceof HttpResponse) { HttpResponse response = (HttpResponse) message; ByteBufUtil.writeAscii(buf, response.protocolVersion().text()); buf.writeByte(SP); buf.writeBytes(String.valueOf(response.status().code()).getBytes(CharsetUtil.US_ASCII)); buf.writeByte(SP); ByteBufUtil.writeAscii(buf, response.status().reasonPhrase()); buf.writeBytes(CRLF); } else { throw new UnsupportedMessageTypeException( "Unsupported type " + StringUtil.simpleClassName(message)); } }
@Override public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if (msg instanceof HttpRequest) { HttpRequest request = this.request = (HttpRequest) msg; URI uri = new URI(request.uri()); if (!uri.getPath().startsWith("/form")) { // Write Menu writeMenu(ctx); return; } responseContent.setLength(0); responseContent.append("WELCOME TO THE WILD WILD WEB SERVER\r\n"); responseContent.append("===================================\r\n"); responseContent.append("VERSION: " + request.protocolVersion().text() + "\r\n"); responseContent.append("REQUEST_URI: " + request.uri() + "\r\n\r\n"); responseContent.append("\r\n\r\n"); // new getMethod for (Entry<CharSequence, CharSequence> entry : request.headers()) { responseContent.append("HEADER: " + entry.getKey() + '=' + entry.getValue() + "\r\n"); } responseContent.append("\r\n\r\n"); // new getMethod Set<Cookie> cookies; String value = request.headers().getAndConvert(HttpHeaderNames.COOKIE); if (value == null) { cookies = Collections.emptySet(); } else { cookies = ServerCookieDecoder.STRICT.decode(value); } for (Cookie cookie : cookies) { responseContent.append("COOKIE: " + cookie + "\r\n"); } responseContent.append("\r\n\r\n"); QueryStringDecoder decoderQuery = new QueryStringDecoder(request.uri()); Map<String, List<String>> uriAttributes = decoderQuery.parameters(); for (Entry<String, List<String>> attr : uriAttributes.entrySet()) { for (String attrVal : attr.getValue()) { responseContent.append("URI: " + attr.getKey() + '=' + attrVal + "\r\n"); } } responseContent.append("\r\n\r\n"); // if GET Method: should not try to create a HttpPostRequestDecoder if (request.method().equals(HttpMethod.GET)) { // GET Method: should not try to create a HttpPostRequestDecoder // So stop here responseContent.append("\r\n\r\nEND OF GET CONTENT\r\n"); // Not now: LastHttpContent will be sent writeResponse(ctx.channel()); return; } try { decoder = new HttpPostRequestDecoder(factory, request); } catch (ErrorDataDecoderException e1) { e1.printStackTrace(); responseContent.append(e1.getMessage()); writeResponse(ctx.channel()); ctx.channel().close(); return; } readingChunks = HttpHeaderUtil.isTransferEncodingChunked(request); responseContent.append("Is Chunked: " + readingChunks + "\r\n"); responseContent.append("IsMultipart: " + decoder.isMultipart() + "\r\n"); if (readingChunks) { // Chunk version responseContent.append("Chunks: "); readingChunks = true; } } // check if the decoder was constructed before // if not it handles the form get if (decoder != null) { if (msg instanceof HttpContent) { // New chunk is received HttpContent chunk = (HttpContent) msg; try { decoder.offer(chunk); } catch (ErrorDataDecoderException e1) { e1.printStackTrace(); responseContent.append(e1.getMessage()); writeResponse(ctx.channel()); ctx.channel().close(); return; } responseContent.append('o'); // example of reading chunk by chunk (minimize memory usage due to // Factory) readHttpDataChunkByChunk(); // example of reading only if at the end if (chunk instanceof LastHttpContent) { writeResponse(ctx.channel()); readingChunks = false; reset(); } } } else { writeResponse(ctx.channel()); } }