View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.fcgi.generator;
20  
21  import java.nio.ByteBuffer;
22  import java.nio.charset.Charset;
23  import java.nio.charset.StandardCharsets;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import org.eclipse.jetty.fcgi.FCGI;
28  import org.eclipse.jetty.http.HttpField;
29  import org.eclipse.jetty.http.HttpFields;
30  import org.eclipse.jetty.http.HttpStatus;
31  import org.eclipse.jetty.io.ByteBufferPool;
32  import org.eclipse.jetty.util.BufferUtil;
33  import org.eclipse.jetty.util.Callback;
34  
35  public class ServerGenerator extends Generator
36  {
37      private static final byte[] STATUS = new byte[]{'S', 't', 'a', 't', 'u', 's'};
38      private static final byte[] COLON = new byte[]{':', ' '};
39      private static final byte[] EOL = new byte[]{'\r', '\n'};
40  
41      private final boolean sendStatus200;
42  
43      public ServerGenerator(ByteBufferPool byteBufferPool)
44      {
45          this(byteBufferPool, true);
46      }
47  
48      public ServerGenerator(ByteBufferPool byteBufferPool, boolean sendStatus200)
49      {
50          super(byteBufferPool);
51          this.sendStatus200 = sendStatus200;
52      }
53  
54      public Result generateResponseHeaders(int request, int code, String reason, HttpFields fields, Callback callback)
55      {
56          request &= 0xFF_FF;
57  
58          final Charset utf8 = StandardCharsets.UTF_8;
59          List<byte[]> bytes = new ArrayList<>(fields.size() * 2);
60          int length = 0;
61  
62          if (code != 200 || sendStatus200)
63          {
64              // Special 'Status' header
65              bytes.add(STATUS);
66              length += STATUS.length + COLON.length;
67              if (reason == null)
68                  reason = HttpStatus.getMessage(code);
69              byte[] responseBytes = (code + " " + reason).getBytes(utf8);
70              bytes.add(responseBytes);
71              length += responseBytes.length + EOL.length;
72          }
73  
74          // Other headers
75          for (HttpField field : fields)
76          {
77              String name = field.getName();
78              byte[] nameBytes = name.getBytes(utf8);
79              bytes.add(nameBytes);
80  
81              String value = field.getValue();
82              byte[] valueBytes = value.getBytes(utf8);
83              bytes.add(valueBytes);
84  
85              length += nameBytes.length + COLON.length;
86              length += valueBytes.length + EOL.length;
87          }
88          // End of headers
89          length += EOL.length;
90  
91          final ByteBuffer buffer = byteBufferPool.acquire(length, true);
92          BufferUtil.clearToFill(buffer);
93  
94          for (int i = 0; i < bytes.size(); i += 2)
95              buffer.put(bytes.get(i)).put(COLON).put(bytes.get(i + 1)).put(EOL);
96          buffer.put(EOL);
97  
98          buffer.flip();
99  
100         return generateContent(request, buffer, true, false, callback, FCGI.FrameType.STDOUT);
101     }
102 
103     public Result generateResponseContent(int request, ByteBuffer content, boolean lastContent, boolean aborted, Callback callback)
104     {
105         if (aborted)
106         {
107             Result result = new Result(byteBufferPool, callback);
108             if (lastContent)
109                 result.append(generateEndRequest(request, true), true);
110             else
111                 result.append(BufferUtil.EMPTY_BUFFER, false);
112             return result;
113         }
114         else
115         {
116             Result result = generateContent(request, content, false, lastContent, callback, FCGI.FrameType.STDOUT);
117             if (lastContent)
118                 result.append(generateEndRequest(request, false), true);
119             return result;
120         }
121     }
122 
123     private ByteBuffer generateEndRequest(int request, boolean aborted)
124     {
125         request &= 0xFF_FF;
126         ByteBuffer endRequestBuffer = byteBufferPool.acquire(8, false);
127         BufferUtil.clearToFill(endRequestBuffer);
128         endRequestBuffer.putInt(0x01_03_00_00 + request);
129         endRequestBuffer.putInt(0x00_08_00_00);
130         endRequestBuffer.putInt(aborted ? 1 : 0);
131         endRequestBuffer.putInt(0);
132         endRequestBuffer.flip();
133         return endRequestBuffer;
134     }
135 }