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