View Javadoc

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