View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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.ajp;
20  
21  import java.io.IOException;
22  import java.io.UnsupportedEncodingException;
23  import java.util.HashMap;
24  
25  import org.eclipse.jetty.http.AbstractGenerator;
26  import org.eclipse.jetty.http.HttpFields;
27  import org.eclipse.jetty.http.HttpGenerator;
28  import org.eclipse.jetty.http.HttpTokens;
29  import org.eclipse.jetty.http.HttpVersions;
30  import org.eclipse.jetty.io.Buffer;
31  import org.eclipse.jetty.io.Buffers;
32  import org.eclipse.jetty.io.ByteArrayBuffer;
33  import org.eclipse.jetty.io.EndPoint;
34  import org.eclipse.jetty.io.EofException;
35  import org.eclipse.jetty.util.StringUtil;
36  import org.eclipse.jetty.util.log.Log;
37  import org.eclipse.jetty.util.log.Logger;
38  
39  /**
40   *
41   *
42   */
43  public class Ajp13Generator extends AbstractGenerator
44  {
45      private static final Logger LOG = Log.getLogger(Ajp13Generator.class);
46  
47      private static HashMap __headerHash = new HashMap();
48  
49      static
50      {
51          byte[] xA001 =
52          { (byte)0xA0, (byte)0x01 };
53          byte[] xA002 =
54          { (byte)0xA0, (byte)0x02 };
55          byte[] xA003 =
56          { (byte)0xA0, (byte)0x03 };
57          byte[] xA004 =
58          { (byte)0xA0, (byte)0x04 };
59          byte[] xA005 =
60          { (byte)0xA0, (byte)0x05 };
61          byte[] xA006 =
62          { (byte)0xA0, (byte)0x06 };
63          byte[] xA007 =
64          { (byte)0xA0, (byte)0x07 };
65          byte[] xA008 =
66          { (byte)0xA0, (byte)0x08 };
67          byte[] xA009 =
68          { (byte)0xA0, (byte)0x09 };
69          byte[] xA00A =
70          { (byte)0xA0, (byte)0x0A };
71          byte[] xA00B =
72          { (byte)0xA0, (byte)0x0B };
73          __headerHash.put("Content-Type",xA001);
74          __headerHash.put("Content-Language",xA002);
75          __headerHash.put("Content-Length",xA003);
76          __headerHash.put("Date",xA004);
77          __headerHash.put("Last-Modified",xA005);
78          __headerHash.put("Location",xA006);
79          __headerHash.put("Set-Cookie",xA007);
80          __headerHash.put("Set-Cookie2",xA008);
81          __headerHash.put("Servlet-Engine",xA009);
82          __headerHash.put("Status",xA00A);
83          __headerHash.put("WWW-Authenticate",xA00B);
84  
85      }
86  
87      // A, B ajp response header
88      // 0, 1 ajp int 1 packet length
89      // 9 CPONG response Code
90      private static final byte[] AJP13_CPONG_RESPONSE =
91      { 'A', 'B', 0, 1, 9 };
92  
93      private static final byte[] AJP13_END_RESPONSE =
94      { 'A', 'B', 0, 2, 5, 1 };
95  
96      // AB ajp respose
97      // 0, 3 int = 3 packets in length
98      // 6, send signal to get more data
99      // 31, -7 byte values for int 8185 = (8 * 1024) - 7 MAX_DATA
100     private static final byte[] AJP13_MORE_CONTENT =
101     { 'A', 'B', 0, 3, 6, 31, -7 };
102 
103     private static String SERVER = "Server: Jetty(7.x.x)";
104 
105     public static void setServerVersion(String version)
106     {
107         SERVER = "Jetty(" + version + ")";
108     }
109 
110     /* ------------------------------------------------------------ */
111     private boolean _expectMore = false;
112 
113     private boolean _needMore = false;
114 
115     private boolean _needEOC = false;
116 
117     private boolean _bufferPrepared = false;
118 
119     /* ------------------------------------------------------------ */
120     public Ajp13Generator(Buffers buffers, EndPoint io)
121     {
122         super(buffers,io);
123     }
124 
125     /* ------------------------------------------------------------ */
126     @Override
127     public boolean isRequest()
128     {
129         return false;
130     }
131 
132     /* ------------------------------------------------------------ */
133     @Override
134     public boolean isResponse()
135     {
136         return true;
137     }
138 
139     /* ------------------------------------------------------------ */
140     @Override
141     public void reset()
142     {
143         super.reset();
144 
145         _needEOC = false;
146         _needMore = false;
147         _expectMore = false;
148         _bufferPrepared = false;
149         _last = false;
150 
151         _state = STATE_HEADER;
152 
153         _status = 0;
154         _version = HttpVersions.HTTP_1_1_ORDINAL;
155         _reason = null;
156         _method = null;
157         _uri = null;
158 
159         _contentWritten = 0;
160         _contentLength = HttpTokens.UNKNOWN_CONTENT;
161         _last = false;
162         _head = false;
163         _noContent = false;
164         _persistent = true;
165 
166         _header = null; // Buffer for HTTP header (and maybe small _content)
167         _buffer = null; // Buffer for copy of passed _content
168         _content = null; // Buffer passed to addContent
169 
170     }
171 
172     /* ------------------------------------------------------------ */
173     @Override
174     public int getContentBufferSize()
175     {
176         try
177         {
178             initContent();
179         }
180         catch (IOException e)
181         {
182             throw new RuntimeException(e);
183         }
184         return super.getContentBufferSize() - 7;
185     }
186 
187     /* ------------------------------------------------------------ */
188     @Override
189     public void increaseContentBufferSize(int contentBufferSize)
190     {
191         // Not supported with AJP
192     }
193 
194     /* ------------------------------------------------------------ */
195     /**
196      * Add content.
197      *
198      * @param content
199      * @param last
200      * @throws IllegalArgumentException
201      *             if <code>content</code> is {@link Buffer#isImmutable immutable}.
202      * @throws IllegalStateException
203      *             If the request is not expecting any more content, or if the buffers are full and cannot be flushed.
204      * @throws IOException
205      *             if there is a problem flushing the buffers.
206      */
207     public void addContent(Buffer content, boolean last) throws IOException
208     {
209         if (_noContent)
210         {
211             content.clear();
212             return;
213         }
214 
215         if (content.isImmutable())
216             throw new IllegalArgumentException("immutable");
217 
218         if (_last || _state == STATE_END)
219         {
220             LOG.debug("Ignoring extra content {}",content);
221             content.clear();
222             return;
223         }
224         _last = last;
225 
226         if (!_endp.isOpen())
227         {
228             _state = STATE_END;
229             return;
230         }
231 
232         // Handle any unfinished business?
233         if (_content != null && _content.length() > 0)
234         {
235 
236             flushBuffer();
237             if (_content != null && _content.length() > 0)
238                 throw new IllegalStateException("FULL");
239         }
240 
241         _content = content;
242 
243         _contentWritten += content.length();
244 
245         // Handle the _content
246         if (_head)
247         {
248             content.clear();
249             _content = null;
250         }
251         else
252         {
253             // Yes - so we better check we have a buffer
254             initContent();
255             // Copy _content to buffer;
256             int len = 0;
257             len = _buffer.put(_content);
258 
259             // make sure there is space for a trailing null
260             if (len > 0 && _buffer.space() == 0)
261             {
262                 len--;
263                 _buffer.setPutIndex(_buffer.putIndex() - 1);
264             }
265 
266             _content.skip(len);
267 
268             if (_content.length() == 0)
269                 _content = null;
270         }
271     }
272 
273     /* ------------------------------------------------------------ */
274     /**
275      * Prepare buffer for unchecked writes. Prepare the generator buffer to receive unchecked writes
276      *
277      * @return the available space in the buffer.
278      * @throws IOException
279      */
280     @Override
281     public int prepareUncheckedAddContent() throws IOException
282     {
283         if (_noContent)
284             return -1;
285 
286         if (_last || _state == STATE_END)
287             throw new IllegalStateException("Closed");
288 
289         if (!_endp.isOpen())
290         {
291             _state = STATE_END;
292             return -1;
293         }
294 
295         // Handle any unfinished business?
296         Buffer content = _content;
297         if (content != null && content.length() > 0)
298         {
299             flushBuffer();
300             if (content != null && content.length() > 0)
301                 throw new IllegalStateException("FULL");
302         }
303 
304         // we better check we have a buffer
305         initContent();
306 
307         _contentWritten -= _buffer.length();
308 
309         // Handle the _content
310         if (_head)
311             return Integer.MAX_VALUE;
312 
313         return _buffer.space() - 1;
314     }
315 
316     /* ------------------------------------------------------------ */
317     @Override
318     public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
319     {
320         if (_state != STATE_HEADER)
321             return;
322 
323         if (_last && !allContentAdded)
324             throw new IllegalStateException("last?");
325         _last = _last | allContentAdded;
326 
327         boolean has_server = false;
328         if (_persistent == null)
329             _persistent = (_version > HttpVersions.HTTP_1_0_ORDINAL);
330 
331         // get a header buffer
332         if (_header == null)
333             _header = _buffers.getHeader();
334 
335         Buffer tmpbuf = _buffer;
336         _buffer = _header;
337 
338         try
339         {
340             // start the header
341             _buffer.put((byte)'A');
342             _buffer.put((byte)'B');
343             addInt(0);
344             _buffer.put((byte)0x4);
345             addInt(_status);
346             if (_reason == null)
347                 _reason = HttpGenerator.getReasonBuffer(_status);
348             if (_reason == null)
349                 _reason = new ByteArrayBuffer(Integer.toString(_status));
350             addBuffer(_reason);
351 
352             if (_status == 100 || _status == 204 || _status == 304)
353             {
354                 _noContent = true;
355                 _content = null;
356             }
357 
358             // allocate 2 bytes for number of headers
359             int field_index = _buffer.putIndex();
360             addInt(0);
361 
362             int num_fields = 0;
363 
364             if (fields != null)
365             {
366                 // Add headers
367                 int s = fields.size();
368                 for (int f = 0; f < s; f++)
369                 {
370                     HttpFields.Field field = fields.getField(f);
371                     if (field == null)
372                         continue;
373                     num_fields++;
374 
375                     byte[] codes = (byte[])__headerHash.get(field.getName());
376                     if (codes != null)
377                     {
378                         _buffer.put(codes);
379                     }
380                     else
381                     {
382                         addString(field.getName());
383                     }
384                     addString(field.getValue());
385                 }
386             }
387 
388             if (!has_server && _status > 100 && getSendServerVersion())
389             {
390                 num_fields++;
391                 addString("Server");
392                 addString(SERVER);
393             }
394 
395             // TODO Add content length if last content known.
396 
397             // insert the number of headers
398             int tmp = _buffer.putIndex();
399             _buffer.setPutIndex(field_index);
400             addInt(num_fields);
401             _buffer.setPutIndex(tmp);
402 
403             // get the payload size ( - 4 bytes for the ajp header)
404             // excluding the
405             // ajp header
406             int payloadSize = _buffer.length() - 4;
407             // insert the total packet size on 2nd and 3rd byte that
408             // was previously
409             // allocated
410             addInt(2,payloadSize);
411         }
412         finally
413         {
414             _buffer = tmpbuf;
415         }
416 
417         _state = STATE_CONTENT;
418 
419     }
420 
421     /* ------------------------------------------------------------ */
422     /**
423      * Complete the message.
424      *
425      * @throws IOException
426      */
427     @Override
428     public void complete() throws IOException
429     {
430         if (_state == STATE_END)
431             return;
432 
433         super.complete();
434 
435         if (_state < STATE_FLUSHING)
436         {
437             _state = STATE_FLUSHING;
438             _needEOC = true;
439         }
440 
441         flushBuffer();
442     }
443 
444     /* ------------------------------------------------------------ */
445     @Override
446     public int flushBuffer() throws IOException
447     {
448         try
449         {
450             if (_state == STATE_HEADER && !_expectMore)
451                 throw new IllegalStateException("State==HEADER");
452             prepareBuffers();
453 
454             if (_endp == null)
455             {
456                 // TODO - probably still needed!
457                 // if (_rneedMore && _buffe != null)
458                 // {
459                 // if(!_hasSentEOC)
460                 // _buffer.put(AJP13_MORE_CONTENT);
461                 // }
462                 if (!_expectMore && _needEOC && _buffer != null)
463                 {
464                     _buffer.put(AJP13_END_RESPONSE);
465                 }
466                 _needEOC = false;
467                 return 0;
468             }
469 
470             // Keep flushing while there is something to flush
471             // (except break below)
472             int total = 0;
473             long last_len = -1;
474             Flushing: while (true)
475             {
476                 int len = -1;
477                 int to_flush = ((_header != null && _header.length() > 0)?4:0) | ((_buffer != null && _buffer.length() > 0)?2:0);
478 
479                 switch (to_flush)
480                 {
481                     case 7:
482                         throw new IllegalStateException(); // should
483                         // never
484                         // happen!
485                     case 6:
486                         len = _endp.flush(_header,_buffer,null);
487 
488                         break;
489                     case 5:
490                         throw new IllegalStateException(); // should
491                         // never
492                         // happen!
493                     case 4:
494                         len = _endp.flush(_header);
495                         break;
496                     case 3:
497                         throw new IllegalStateException(); // should
498                         // never
499                         // happen!
500                     case 2:
501                         len = _endp.flush(_buffer);
502 
503                         break;
504                     case 1:
505                         throw new IllegalStateException(); // should
506                         // never
507                         // happen!
508                     case 0:
509                     {
510                         // Nothing more we can write now.
511                         if (_header != null)
512                             _header.clear();
513 
514                         _bufferPrepared = false;
515 
516                         if (_buffer != null)
517                         {
518                             _buffer.clear();
519 
520                             // reserve some space for the
521                             // header
522                             _buffer.setPutIndex(7);
523                             _buffer.setGetIndex(7);
524 
525                             // Special case handling for
526                             // small left over buffer from
527                             // an addContent that caused a
528                             // buffer flush.
529                             if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
530                             {
531 
532                                 _buffer.put(_content);
533                                 _content.clear();
534                                 _content = null;
535                                 break Flushing;
536                             }
537 
538                         }
539 
540                         // Are we completely finished for now?
541                         if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
542                         {
543                             if (_state == STATE_FLUSHING)
544                                 _state = STATE_END;
545 
546                             // if (_state == STATE_END)
547                             // {
548                             // _endp.close();
549                             // }
550                             //
551 
552                             break Flushing;
553                         }
554 
555                         // Try to prepare more to write.
556                         prepareBuffers();
557                     }
558                 }
559 
560                 // If we failed to flush anything twice in a row
561                 // break
562                 if (len <= 0)
563                 {
564                     if (last_len <= 0)
565                         break Flushing;
566                     break;
567                 }
568                 last_len = len;
569                 total += len;
570             }
571 
572             return total;
573         }
574         catch (IOException e)
575         {
576             LOG.ignore(e);
577             throw (e instanceof EofException)?e:new EofException(e);
578         }
579 
580     }
581 
582     /* ------------------------------------------------------------ */
583     private void prepareBuffers()
584     {
585         if (!_bufferPrepared)
586         {
587 
588             // Refill buffer if possible
589             if (_content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0)
590             {
591 
592                 int len = _buffer.put(_content);
593 
594                 // Make sure there is space for a trailing null
595                 if (len > 0 && _buffer.space() == 0)
596                 {
597                     len--;
598                     _buffer.setPutIndex(_buffer.putIndex() - 1);
599                 }
600                 _content.skip(len);
601 
602                 if (_content.length() == 0)
603                     _content = null;
604 
605                 if (_buffer.length() == 0)
606                 {
607                     _content = null;
608                 }
609             }
610 
611             // add header if needed
612             if (_buffer != null)
613             {
614 
615                 int payloadSize = _buffer.length();
616 
617                 // 4 bytes for the ajp header
618                 // 1 byte for response type
619                 // 2 bytes for the response size
620                 // 1 byte because we count from zero??
621 
622                 if (payloadSize > 0)
623                 {
624                     _bufferPrepared = true;
625 
626                     _buffer.put((byte)0);
627                     int put = _buffer.putIndex();
628                     _buffer.setGetIndex(0);
629                     _buffer.setPutIndex(0);
630                     _buffer.put((byte)'A');
631                     _buffer.put((byte)'B');
632                     addInt(payloadSize + 4);
633                     _buffer.put((byte)3);
634                     addInt(payloadSize);
635                     _buffer.setPutIndex(put);
636                 }
637             }
638 
639             if (_needMore)
640             {
641 
642                 if (_header == null)
643                 {
644                     _header = _buffers.getHeader();
645                 }
646 
647                 if (_buffer == null && _header != null && _header.space() >= AJP13_MORE_CONTENT.length)
648                 {
649                     _header.put(AJP13_MORE_CONTENT);
650                     _needMore = false;
651                 }
652                 else if (_buffer != null && _buffer.space() >= AJP13_MORE_CONTENT.length)
653                 {
654                     // send closing packet if all contents
655                     // are added
656                     _buffer.put(AJP13_MORE_CONTENT);
657                     _needMore = false;
658                     _bufferPrepared = true;
659                 }
660 
661             }
662 
663             if (!_expectMore && _needEOC)
664             {
665                 if (_buffer == null && _header.space() >= AJP13_END_RESPONSE.length)
666                 {
667 
668                     _header.put(AJP13_END_RESPONSE);
669                     _needEOC = false;
670                 }
671                 else if (_buffer != null && _buffer.space() >= AJP13_END_RESPONSE.length)
672                 {
673                     // send closing packet if all contents
674                     // are added
675 
676                     _buffer.put(AJP13_END_RESPONSE);
677                     _needEOC = false;
678                     _bufferPrepared = true;
679                 }
680             }
681         }
682     }
683 
684     /* ------------------------------------------------------------ */
685     @Override
686     public boolean isComplete()
687     {
688         return !_expectMore && _state == STATE_END;
689     }
690 
691     /* ------------------------------------------------------------ */
692     private void initContent() throws IOException
693     {
694         if (_buffer == null)
695         {
696             _buffer = _buffers.getBuffer();
697             _buffer.setPutIndex(7);
698             _buffer.setGetIndex(7);
699         }
700     }
701 
702     /* ------------------------------------------------------------ */
703     private void addInt(int i)
704     {
705         _buffer.put((byte)((i >> 8) & 0xFF));
706         _buffer.put((byte)(i & 0xFF));
707     }
708 
709     /* ------------------------------------------------------------ */
710     private void addInt(int startIndex, int i)
711     {
712         _buffer.poke(startIndex,(byte)((i >> 8) & 0xFF));
713         _buffer.poke((startIndex + 1),(byte)(i & 0xFF));
714     }
715 
716     /* ------------------------------------------------------------ */
717     private void addString(String str) throws UnsupportedEncodingException
718     {
719         if (str == null)
720         {
721             addInt(0xFFFF);
722             return;
723         }
724 
725         // TODO - need to use a writer to convert, to avoid this hacky
726         // conversion and temp buffer
727         byte[] b = str.getBytes(StringUtil.__ISO_8859_1);
728 
729         addInt(b.length);
730 
731         _buffer.put(b);
732         _buffer.put((byte)0);
733     }
734 
735     /* ------------------------------------------------------------ */
736     private void addBuffer(Buffer b)
737     {
738         if (b == null)
739         {
740             addInt(0xFFFF);
741             return;
742         }
743 
744         addInt(b.length());
745         _buffer.put(b);
746         _buffer.put((byte)0);
747     }
748 
749     /* ------------------------------------------------------------ */
750     public void getBodyChunk() throws IOException
751     {
752         ByteArrayBuffer bf = new ByteArrayBuffer(AJP13_MORE_CONTENT);
753         _endp.flush(bf);
754     }
755 
756     /* ------------------------------------------------------------ */
757     public void gotBody()
758     {
759         _needMore = false;
760         _expectMore = false;
761     }
762 
763     /* ------------------------------------------------------------ */
764     public void sendCPong() throws IOException
765     {
766 
767         Buffer buff = _buffers.getBuffer();
768         buff.put(AJP13_CPONG_RESPONSE);
769 
770         // flushing cpong response
771         do
772         {
773             _endp.flush(buff);
774         }
775         while (buff.length() > 0);
776         _buffers.returnBuffer(buff);
777 
778         reset();
779 
780     }
781 
782 }