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
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
80
81
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
89
90
91
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;
162 _buffer = null;
163 _content = null;
164
165
166 }
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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
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
222 if (_head)
223 {
224
225 content.clear();
226 _content = null;
227 }
228 else
229 {
230
231 initContent();
232
233 int len = 0;
234 len = _buffer.put(_content);
235
236
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
253
254
255
256
257
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
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
286 if (_head)
287 return false;
288
289
290 initContent();
291
292
293
294 _buffer.put(b);
295
296 return _buffer.space() <= 1;
297 }
298
299
300
301
302
303
304
305
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
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
333 initContent();
334
335 _contentWritten -= _buffer.length();
336
337
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
360 if (_header == null)
361 _header = _buffers.getHeader();
362
363 Buffer tmpbuf = _buffer;
364 _buffer = _header;
365
366 try
367 {
368
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
388 int field_index = _buffer.putIndex();
389 addInt(0);
390
391 int num_fields = 0;
392
393 if (fields != null)
394 {
395
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
425
426
427 int tmp = _buffer.putIndex();
428 _buffer.setPutIndex(field_index);
429 addInt(num_fields);
430 _buffer.setPutIndex(tmp);
431
432
433
434
435 int payloadSize = _buffer.length() - 4;
436
437
438
439 addInt(2, payloadSize);
440 }
441 finally
442 {
443 _buffer = tmpbuf;
444 }
445
446
447 _state = STATE_CONTENT;
448
449 }
450
451
452
453
454
455
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
487
488
489
490
491
492 if (!_expectMore && _needEOC && _buffer != null)
493 {
494 _buffer.put(AJP13_END_RESPONSE);
495 }
496 _needEOC = false;
497 return 0;
498 }
499
500
501
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();
514
515
516 case 6:
517 len = _endp.flush(_header, _buffer, null);
518
519 break;
520 case 5:
521 throw new IllegalStateException();
522
523
524 case 4:
525 len = _endp.flush(_header);
526 break;
527 case 3:
528 throw new IllegalStateException();
529
530
531 case 2:
532 len = _endp.flush(_buffer);
533
534 break;
535 case 1:
536 throw new IllegalStateException();
537
538
539 case 0:
540 {
541
542 if (_header != null)
543 _header.clear();
544
545 _bufferPrepared = false;
546
547 if (_buffer != null)
548 {
549 _buffer.clear();
550
551
552
553 _buffer.setPutIndex(7);
554 _buffer.setGetIndex(7);
555
556
557
558
559
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
574 if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
575 {
576 if (_state == STATE_FLUSHING)
577 _state = STATE_END;
578
579
580
581
582
583
584
585 break Flushing;
586 }
587
588
589 prepareBuffers();
590 }
591 }
592
593
594
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
622 if (_content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0)
623 {
624
625 int len = _buffer.put(_content);
626
627
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
645 if (_buffer != null)
646 {
647
648 int payloadSize = _buffer.length();
649
650
651
652
653
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
688
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
707
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
759
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
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 }