1
2
3
4
5
6
7
8
9
10
11
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
83
84
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
92
93
94
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
135 @Override
136 public void reset(boolean returnBuffers)
137 {
138 super.reset(returnBuffers);
139
140 _needEOC = false;
141 _needMore = false;
142 _expectMore = false;
143 _bufferPrepared = false;
144 _last = false;
145
146 _state = STATE_HEADER;
147
148 _status = 0;
149 _version = HttpVersions.HTTP_1_1_ORDINAL;
150 _reason = null;
151 _method = null;
152 _uri = null;
153
154 _contentWritten = 0;
155 _contentLength = HttpTokens.UNKNOWN_CONTENT;
156 _last = false;
157 _head = false;
158 _noContent = false;
159 _persistent = true;
160
161 _header = null;
162 _buffer = null;
163 _content = null;
164
165 }
166
167
168 @Override
169 public int getContentBufferSize()
170 {
171 try
172 {
173 initContent();
174 }
175 catch (IOException e)
176 {
177 throw new RuntimeException(e);
178 }
179 return super.getContentBufferSize() - 7;
180 }
181
182
183 @Override
184 public void increaseContentBufferSize(int contentBufferSize)
185 {
186
187 }
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 public void addContent(Buffer content, boolean last) throws IOException
203 {
204 if (_noContent)
205 {
206 content.clear();
207 return;
208 }
209
210 if (content.isImmutable())
211 throw new IllegalArgumentException("immutable");
212
213 if (_last || _state == STATE_END)
214 {
215 LOG.debug("Ignoring extra content {}",content);
216 content.clear();
217 return;
218 }
219 _last = last;
220
221 if (!_endp.isOpen())
222 {
223 _state = STATE_END;
224 return;
225 }
226
227
228 if (_content != null && _content.length() > 0)
229 {
230
231 flushBuffer();
232 if (_content != null && _content.length() > 0)
233 throw new IllegalStateException("FULL");
234 }
235
236 _content = content;
237
238 _contentWritten += content.length();
239
240
241 if (_head)
242 {
243
244 content.clear();
245 _content = null;
246 }
247 else
248 {
249
250 initContent();
251
252 int len = 0;
253 len = _buffer.put(_content);
254
255
256 if (len > 0 && _buffer.space() == 0)
257 {
258 len--;
259 _buffer.setPutIndex(_buffer.putIndex() - 1);
260 }
261
262 _content.skip(len);
263
264 if (_content.length() == 0)
265 _content = null;
266 }
267 }
268
269
270
271
272
273
274
275
276
277
278 public boolean addContent(byte b) throws IOException
279 {
280
281 if (_noContent)
282 return false;
283
284 if (_last || _state == STATE_END)
285 throw new IllegalStateException("Closed");
286
287 if (!_endp.isOpen())
288 {
289 _state = STATE_END;
290 return false;
291 }
292
293
294 if (_content != null && _content.length() > 0)
295 {
296 flushBuffer();
297 if (_content != null && _content.length() > 0)
298 throw new IllegalStateException("FULL");
299 }
300
301 _contentWritten++;
302
303
304 if (_head)
305 return false;
306
307
308 initContent();
309
310
311
312 _buffer.put(b);
313
314 return _buffer.space() <= 1;
315 }
316
317
318
319
320
321
322
323
324 @Override
325 public int prepareUncheckedAddContent() throws IOException
326 {
327 if (_noContent)
328 return -1;
329
330 if (_last || _state == STATE_END)
331 throw new IllegalStateException("Closed");
332
333 if (!_endp.isOpen())
334 {
335 _state = STATE_END;
336 return -1;
337 }
338
339
340 Buffer content = _content;
341 if (content != null && content.length() > 0)
342 {
343 flushBuffer();
344 if (content != null && content.length() > 0)
345 throw new IllegalStateException("FULL");
346 }
347
348
349 initContent();
350
351 _contentWritten -= _buffer.length();
352
353
354 if (_head)
355 return Integer.MAX_VALUE;
356
357 return _buffer.space() - 1;
358 }
359
360
361 @Override
362 public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
363 {
364 if (_state != STATE_HEADER)
365 return;
366
367 if (_last && !allContentAdded)
368 throw new IllegalStateException("last?");
369 _last = _last | allContentAdded;
370
371 boolean has_server = false;
372 if (_persistent == null)
373 _persistent = (_version > HttpVersions.HTTP_1_0_ORDINAL);
374
375
376 if (_header == null)
377 _header = _buffers.getHeader();
378
379 Buffer tmpbuf = _buffer;
380 _buffer = _header;
381
382 try
383 {
384
385 _buffer.put((byte)'A');
386 _buffer.put((byte)'B');
387 addInt(0);
388 _buffer.put((byte)0x4);
389 addInt(_status);
390 if (_reason == null)
391 _reason = HttpGenerator.getReasonBuffer(_status);
392 if (_reason == null)
393 _reason = new ByteArrayBuffer(Integer.toString(_status));
394 addBuffer(_reason);
395
396 if (_status == 100 || _status == 204 || _status == 304)
397 {
398 _noContent = true;
399 _content = null;
400 }
401
402
403 int field_index = _buffer.putIndex();
404 addInt(0);
405
406 int num_fields = 0;
407
408 if (fields != null)
409 {
410
411 int s = fields.size();
412 for (int f = 0; f < s; f++)
413 {
414 HttpFields.Field field = fields.getField(f);
415 if (field == null)
416 continue;
417 num_fields++;
418
419 byte[] codes = (byte[])__headerHash.get(field.getName());
420 if (codes != null)
421 {
422 _buffer.put(codes);
423 }
424 else
425 {
426 addString(field.getName());
427 }
428 addString(field.getValue());
429 }
430 }
431
432 if (!has_server && _status > 100 && getSendServerVersion())
433 {
434 num_fields++;
435 addString("Server");
436 addString(SERVER);
437 }
438
439
440
441
442 int tmp = _buffer.putIndex();
443 _buffer.setPutIndex(field_index);
444 addInt(num_fields);
445 _buffer.setPutIndex(tmp);
446
447
448
449
450 int payloadSize = _buffer.length() - 4;
451
452
453
454 addInt(2,payloadSize);
455 }
456 finally
457 {
458 _buffer = tmpbuf;
459 }
460
461 _state = STATE_CONTENT;
462
463 }
464
465
466
467
468
469
470
471 @Override
472 public void complete() throws IOException
473 {
474 if (_state == STATE_END)
475 return;
476
477 super.complete();
478
479 if (_state < STATE_FLUSHING)
480 {
481 _state = STATE_FLUSHING;
482 _needEOC = true;
483 }
484
485 flushBuffer();
486 }
487
488
489 @Override
490 public long flushBuffer() throws IOException
491 {
492 try
493 {
494 if (_state == STATE_HEADER && !_expectMore)
495 throw new IllegalStateException("State==HEADER");
496 prepareBuffers();
497
498 if (_endp == null)
499 {
500
501
502
503
504
505
506 if (!_expectMore && _needEOC && _buffer != null)
507 {
508 _buffer.put(AJP13_END_RESPONSE);
509 }
510 _needEOC = false;
511 return 0;
512 }
513
514
515
516 int total = 0;
517 long last_len = -1;
518 Flushing: while (true)
519 {
520 int len = -1;
521 int to_flush = ((_header != null && _header.length() > 0)?4:0) | ((_buffer != null && _buffer.length() > 0)?2:0);
522
523 switch (to_flush)
524 {
525 case 7:
526 throw new IllegalStateException();
527
528
529 case 6:
530 len = _endp.flush(_header,_buffer,null);
531
532 break;
533 case 5:
534 throw new IllegalStateException();
535
536
537 case 4:
538 len = _endp.flush(_header);
539 break;
540 case 3:
541 throw new IllegalStateException();
542
543
544 case 2:
545 len = _endp.flush(_buffer);
546
547 break;
548 case 1:
549 throw new IllegalStateException();
550
551
552 case 0:
553 {
554
555 if (_header != null)
556 _header.clear();
557
558 _bufferPrepared = false;
559
560 if (_buffer != null)
561 {
562 _buffer.clear();
563
564
565
566 _buffer.setPutIndex(7);
567 _buffer.setGetIndex(7);
568
569
570
571
572
573 if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
574 {
575
576 _buffer.put(_content);
577 _content.clear();
578 _content = null;
579 break Flushing;
580 }
581
582 }
583
584
585 if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
586 {
587 if (_state == STATE_FLUSHING)
588 _state = STATE_END;
589
590
591
592
593
594
595
596 break Flushing;
597 }
598
599
600 prepareBuffers();
601 }
602 }
603
604
605
606 if (len <= 0)
607 {
608 if (last_len <= 0)
609 break Flushing;
610 break;
611 }
612 last_len = len;
613 total += len;
614 }
615
616 return total;
617 }
618 catch (IOException e)
619 {
620 LOG.ignore(e);
621 throw (e instanceof EofException)?e:new EofException(e);
622 }
623
624 }
625
626
627 private void prepareBuffers()
628 {
629 if (!_bufferPrepared)
630 {
631
632
633 if (_content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0)
634 {
635
636 int len = _buffer.put(_content);
637
638
639 if (len > 0 && _buffer.space() == 0)
640 {
641 len--;
642 _buffer.setPutIndex(_buffer.putIndex() - 1);
643 }
644 _content.skip(len);
645
646 if (_content.length() == 0)
647 _content = null;
648
649 if (_buffer.length() == 0)
650 {
651 _content = null;
652 }
653 }
654
655
656 if (_buffer != null)
657 {
658
659 int payloadSize = _buffer.length();
660
661
662
663
664
665
666 if (payloadSize > 0)
667 {
668 _bufferPrepared = true;
669
670 _buffer.put((byte)0);
671 int put = _buffer.putIndex();
672 _buffer.setGetIndex(0);
673 _buffer.setPutIndex(0);
674 _buffer.put((byte)'A');
675 _buffer.put((byte)'B');
676 addInt(payloadSize + 4);
677 _buffer.put((byte)3);
678 addInt(payloadSize);
679 _buffer.setPutIndex(put);
680 }
681 }
682
683 if (_needMore)
684 {
685
686 if (_header == null)
687 {
688 _header = _buffers.getHeader();
689 }
690
691 if (_buffer == null && _header != null && _header.space() >= AJP13_MORE_CONTENT.length)
692 {
693 _header.put(AJP13_MORE_CONTENT);
694 _needMore = false;
695 }
696 else if (_buffer != null && _buffer.space() >= AJP13_MORE_CONTENT.length)
697 {
698
699
700 _buffer.put(AJP13_MORE_CONTENT);
701 _needMore = false;
702 _bufferPrepared = true;
703 }
704
705 }
706
707 if (!_expectMore && _needEOC)
708 {
709 if (_buffer == null && _header.space() >= AJP13_END_RESPONSE.length)
710 {
711
712 _header.put(AJP13_END_RESPONSE);
713 _needEOC = false;
714 }
715 else if (_buffer != null && _buffer.space() >= AJP13_END_RESPONSE.length)
716 {
717
718
719
720 _buffer.put(AJP13_END_RESPONSE);
721 _needEOC = false;
722 _bufferPrepared = true;
723 }
724 }
725 }
726 }
727
728
729 @Override
730 public boolean isComplete()
731 {
732 return !_expectMore && _state == STATE_END;
733 }
734
735
736 private void initContent() throws IOException
737 {
738 if (_buffer == null)
739 {
740 _buffer = _buffers.getBuffer();
741 _buffer.setPutIndex(7);
742 _buffer.setGetIndex(7);
743 }
744 }
745
746
747 private void addInt(int i)
748 {
749 _buffer.put((byte)((i >> 8) & 0xFF));
750 _buffer.put((byte)(i & 0xFF));
751 }
752
753
754 private void addInt(int startIndex, int i)
755 {
756 _buffer.poke(startIndex,(byte)((i >> 8) & 0xFF));
757 _buffer.poke((startIndex + 1),(byte)(i & 0xFF));
758 }
759
760
761 private void addString(String str) throws UnsupportedEncodingException
762 {
763 if (str == null)
764 {
765 addInt(0xFFFF);
766 return;
767 }
768
769
770
771 byte[] b = str.getBytes(StringUtil.__ISO_8859_1);
772
773 addInt(b.length);
774
775 _buffer.put(b);
776 _buffer.put((byte)0);
777 }
778
779
780 private void addBuffer(Buffer b)
781 {
782 if (b == null)
783 {
784 addInt(0xFFFF);
785 return;
786 }
787
788 addInt(b.length());
789 _buffer.put(b);
790 _buffer.put((byte)0);
791 }
792
793
794 public void getBodyChunk() throws IOException
795 {
796 ByteArrayBuffer bf = new ByteArrayBuffer(AJP13_MORE_CONTENT);
797 _endp.flush(bf);
798 }
799
800
801 public void gotBody()
802 {
803 _needMore = false;
804 _expectMore = false;
805 }
806
807
808 public void sendCPong() throws IOException
809 {
810
811 Buffer buff = _buffers.getBuffer();
812 buff.put(AJP13_CPONG_RESPONSE);
813
814
815 do
816 {
817 _endp.flush(buff);
818 }
819 while (buff.length() > 0);
820 _buffers.returnBuffer(buff);
821
822 reset(true);
823
824 }
825
826 }