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