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