модуль хттп импорт "исх/строка" импорт "исх/вперед-назад" импорт "исх/сеть/тцп" фн сериализовать хттп ответ*(р: ХттпОтвет): Строка { пусть ответ := строка.собрать(строка.ф("$стр $цел $стр\r\n", р.версия, р.код, р.состояние)) пусть есть размер контента := ложь цикл [номер]заглавие среди р.заглавия { если заглавие.имя = "Content-Length" { есть размер контента := истина } ответ := строка.собрать(ответ, строка.ф("$стр: $стр\r\n", заглавие.имя, заглавие.значение)) } если ~ есть размер контента { ответ := строка.собрать(ответ, строка.ф("Content-Length: $цел\r\n", длина(р.туловище(:Строка8)))) } ответ := строка.собрать(ответ, "\r\n") если длина(р.туловище) > 0 { ответ := строка.собрать(ответ, р.туловище) } вернуть ответ } фн отправить хттп ответ*(с: тцп.ТцпСоединение, р: ХттпОтвет) { пусть данные := сериализовать хттп ответ(р) с.записать(данные) } фн разобрать хттп обращение*(с: вперед-назад.Крипипаста): ХттпОбращение { пусть сколько читаем = 1024 пусть прочитано := 0 пусть обращение = ХттпОбращение{} пусть данные := "" пусть первая линия := "" пусть добрались до тела := ложь пусть размер контента: Цел64 := -1 пока истина { пусть сколько прочитать: Цел64 := -1 если размер контента > 0 & добрались до тела { сколько прочитать := размер контента - прочитано } если сколько прочитать = 0 { вернуть обращение } пусть новые данные = с.прочитать(сколько читаем) прочитано := прочитано + длина(новые данные) если длина(новые данные) = 0 { вернуть обращение } данные := строка.собрать(данные, новые данные) если ~ добрались до тела { пока длина(данные) > 0 { пусть конец строки = строка.индекс(данные, 0, "\n") если конец строки = -1 { прервать } пусть линия = строка.обрезать пробельные символы(строка.извлечь(данные, 0, конец строки)) данные := строка.извлечь(данные, конец строки + 1, длина(данные(:Строка8)) - конец строки) если линия = "" { если размер контента > 0 { пусть индекс переноса = строка.индекс(данные, 0, "\n") добрались до тела := истина данные := строка.извлечь(данные, индекс переноса + 1, длина(данные(:Строка8)) - индекс переноса) прочитано := длина(данные(:Строка8)) обращение.туловище := данные данные := "" прервать } иначе { вернуть обращение } } если первая линия = "" { первая линия := линия пусть части = строка.разобрать(первая линия, " ") если длина(части) >= 1 { обращение.метод := части[0] } если длина(части) >= 2 { цикл [номер]часть среди части { если номер > 0 & номер < длина(части) - 1 { если номер > 1 { обращение.путь := строка.собрать(обращение.путь, " ") } обращение.путь := строка.собрать(обращение.путь, часть) } } } если длина(части) >= 3 { обращение.версия := части[длина(части) - 1] } } иначе { пусть заглавие = ХттпЗаглавие{} строка.разделить(линия, ":", заглавие.имя, заглавие.значение) заглавие.имя := строка.обрезать пробельные символы(заглавие.имя) заглавие.значение := строка.обрезать пробельные символы(заглавие.значение) если размер контента < 0 & заглавие.имя = "Content-Length" { пусть новый размер контента := 0 пусть номер байта := 0 если строка.извлечь цел(заглавие.значение, номер байта, новый размер контента) { размер контента := новый размер контента } } обращение.заглавия.добавить(заглавие) } } } иначе { обращение.туловище := строка.соединить(обращение.туловище, данные) } } вернуть обращение } фн разобрать хттп ответ*(с: тцп.ТцпСоединение): ХттпОтвет { пусть сколько читаем = 1024 пусть прочитано := 0 пусть ответ = ХттпОтвет{} пусть данные := "" пусть первая линия := "" пусть добрались до тела := ложь пусть размер контента: Цел64 := -1 пока истина { пусть сколько прочитать: Цел64 := -1 если размер контента > 0 & добрались до тела { сколько прочитать := размер контента - прочитано } если сколько прочитать = 0 { вернуть ответ } пусть новые данные = с.прочитать(сколько читаем) прочитано := прочитано + длина(новые данные) если длина(новые данные) = 0 { вернуть ответ } данные := строка.собрать(данные, новые данные) если ~ добрались до тела { пока длина(данные) > 0 { пусть конец строки = строка.индекс(данные, 0, "\n") если конец строки = -1 { прервать } пусть линия = строка.обрезать пробельные символы(строка.извлечь(данные, 0, конец строки)) данные := строка.извлечь(данные, конец строки + 1, длина(данные(:Строка8)) - конец строки) если линия = "" { если размер контента > 0 { добрались до тела := истина прочитано := длина(данные(:Строка8)) ответ.туловище := данные данные := "" прервать } иначе { вернуть ответ } } если первая линия = "" { первая линия := линия пусть части = строка.разобрать(первая линия, " ") если длина(части) >= 1 { ответ.версия := части[0] } если длина(части) >= 2 { пусть новый код := 0 пусть номер байта := 0 если строка.извлечь цел(части[1], номер байта, новый код) { ответ.код := новый код } } если длина(части) >= 3 { цикл [номер]часть среди части { если номер >= 2 { если номер > 2 { ответ.состояние := строка.собрать(ответ.состояние, " ") } ответ.состояние := строка.собрать(ответ.состояние, часть) } } } } иначе { пусть заглавие = ХттпЗаглавие{} строка.разделить(линия, ":", заглавие.имя, заглавие.значение) заглавие.имя := строка.обрезать пробельные символы(заглавие.имя) заглавие.значение := строка.обрезать пробельные символы(заглавие.значение) если размер контента < 0 & заглавие.имя = "Content-Length" { пусть новый размер контента := 0 пусть номер байта := 0 если строка.извлечь цел(заглавие.значение, номер байта, новый размер контента) { размер контента := новый размер контента } } ответ.заглавия.добавить(заглавие) } } } иначе { ответ.туловище := строка.соединить(ответ.туловище, данные) } } вернуть ответ }