diff --git a/ru/04.0.md b/ru/04.0.md
new file mode 100644
index 00000000..3c46b63c
--- /dev/null
+++ b/ru/04.0.md
@@ -0,0 +1,23 @@
+# 4 Пользовательские формы
+
+Пользовательские формы очень часто используются при разработке веб-приложений. Они дают возможность клиенту и серверу устанавливать коммуникацию друг с другом. Если вы - веб-разработчик, Вы должны быть хорошо знакомы с веб-формами; если Вы - программист на C/C++, Вы можете спросить - что такое пользовательская форма?
+
+Форма - это область, которая содержит элементы формы. Пользователь может вносить информацию в элементы формы, такие как текстовые поля, выпадающие списки, радиокнопки, чекбоксы и т.д. Для определения формы используется тэг `
+
+В Go уже есть множество удобных функций для того, чтобы взаимодействовать с пользовательскими формами. Можно легко получить данные из формы в запросе HTTP, они легко интегрируются в Ваши веб-приложения. В разделе 4.1 мы собираемся поговорить о том, как обрабатывать данные из форм в Go. Также, поскольку нельзя доверять любым данным, приходящим со стороны клиента, нужно сначала проверить их перед тем, как использовать. В разделе 4.2 мы поговорим о том, как проверить данные, пришедшие из формы.
+
+Говорится, что HTTP - это протокол без сохранения состояния. Так как проверить, что данные из формы пришли от того же пользователя? И как можно быть уверенным, что одна форма может послать данные за один раз лишь единожды? Мы рассмотрим некоторые детали, касающиеся кук (куки - это информация, сохраняемая на стороне клиента и добавляемая в заголовок запроса, посылаемый на сервер) в разделах 4.3 и 4.4.
+
+Еще один важный случай использования форм - загрузка файлов. В разделе 4.5 Вы научитесь, как это делать, осуществляя контроль размера файла перед тем, как его загрузить, средствами Go.
+
+## Ссылки
+
+- [Содержание](preface.md)
+- Предыдущий раздел: [Итоги главы 3](03.5.md)
+- Следующий раздел: [Работа с формами](04.1.md)
diff --git a/ru/04.1.md b/ru/04.1.md
new file mode 100644
index 00000000..42f10e10
--- /dev/null
+++ b/ru/04.1.md
@@ -0,0 +1,107 @@
+# 4.1 Работа с формами
+
+Перед тем, как начать, давайте посмотрим на простой пример обычной пользовательской формы, сохраненной как `login.gtpl` в папке Вашего проекта:
+
+
+
+
+
+
+
+
+
+
+Эта форма отправит данные по адресу `/login` на сервер. После того, как пользователь нажем кнопку "Войти", данные будут посланы на хэндлер `login`, зарегистрированный маршрутизатором сервера. Нам нужно знать, какой метод используется при этом - POST или GET?
+
+Это легко узнать при помощи пакета `http`. Давайте посмотрим, как обработать данные формы со страницы входа:
+
+ package main
+
+ import (
+ "fmt"
+ "html/template"
+ "log"
+ "net/http"
+ "strings"
+ )
+
+ func sayhelloName(w http.ResponseWriter, r *http.Request) {
+ r.ParseForm() // Анализирует переданные параметры url, затем анализирует пакет ответа для тела POST (тела запроса)
+ // внимание: без вызова метода ParseForm последующие данные не будут получены
+ fmt.Println(r.Form) // печатает информацию на сервере
+ fmt.Println("Путь: ", r.URL.Path)
+ fmt.Println("Схема: ", r.URL.Scheme)
+ fmt.Println(r.Form["url_long"])
+ for k, v := range r.Form {
+ fmt.Println("Ключ: ", k)
+ fmt.Println("Значение: ", strings.Join(v, ""))
+ }
+ fmt.Fprintf(w, "Привет astaxie!") // пишет данные в ответ
+ }
+
+ func login(w http.ResponseWriter, r *http.Request) {
+ fmt.Println("Метод:", r.Method) // получаем информацию о методе запроса
+ if r.Method == "GET" {
+ t, _ := template.ParseFiles("login.gtpl")
+ t.Execute(w, nil)
+ } else {
+ //r.ParseForm()
+ // логическая часть процесса входа
+ fmt.Println("Пользователь:", r.Form["username"])
+ fmt.Println("Пароль:", r.Form["password"])
+ }
+ }
+
+ func main() {
+ http.HandleFunc("/", sayhelloName) // устанавливаем правила маршрутизатора
+ http.HandleFunc("/login", login)
+ err := http.ListenAndServe(":9090", nil) // устанавливаем порт для прослушивания
+ if err != nil {
+ log.Fatal("ListenAndServe: ", err)
+ }
+ }
+
+
+Здесь мы используем `r.Method` для того, чтобы получить информацию о методе запроса, и нам возвращается метод HTTP -"GET", "POST", "PUT" и т.д.
+
+В функции `login` мы использовали метод `r.Method`, чтобы проверить, что это - страница входа или логика обработки информации о входе. Другими словами, мы проверяем, открыл ли пользователь страницу или уже заполнил форму и пытается войти. Сервер отображает страницу только в случае, если запрос идет посредством метода GET, и запускает логику обработки информации о входе, если запрос использует метод POST.
+
+Вы должны увидеть следующий интерфейс после открытия `http://127.0.0.1:9090/login` в браузере:
+
+
+
+Рисунок 4.1 Интерфейс входа пользователя
+
+Сервер ничего не напечатает, пока мы не введем имя пользователя и пароль, потому что хэндлер не будет анализировать данные, пока мы не вызовем `r.ParseForm()`. Давайте добавим `r.ParseForm()` перед `fmt.Println("username:", r.Form["username"])`, скомпилируем программу и вновь протестируем её. Вы обнаружите, что в этом случае информация стала печататься на стороне сервера.
+
+`r.Form` содержит все аргументы запроса, например, строку запроса в URL и данные в POST и PUT. Если в данных есть конфликты, например, параметры имеют одинаковое имя, сервер сохранит данные в срез из множества значений. Документация Go говорит о том, что Go сохраняет данные из запросов GET и POST в разных местах.
+
+Попробуйте изменить значение поля 'action' в форме `http://127.0.0.1:9090/login` на `http://127.0.0.1:9090/login?username=astaxie` в файле `login.gtpl`, протестируйте работу формы, и Вы увидите, что на стороне сервера вывелся срез значений:
+
+
+
+Рисунок 4.2 Сервер печатает данные запроса
+
+Тип поля `request.Form` - это `url.Value`. Данные в нем сохраняются в формате `ключ=значение`.
+
+ v := url.Values{}
+ v.Set("name", "Ava")
+ v.Add("friend", "Jess")
+ v.Add("friend", "Sarah")
+ v.Add("friend", "Zoe")
+ // v.Encode() == "name=Ava&friend=Jess&friend=Sarah&friend=Zoe"
+ fmt.Println(v.Get("name"))
+ fmt.Println(v.Get("friend"))
+ fmt.Println(v["friend"])
+
+**Совет:** Запросы могут получать доступ к данным формы с использованием метода `FormValue()`. Например, можно вместо `r.Form["username"]` использовать `r.FormValue("username")`, и Go вызовет `r.ParseForm` автоматически. Отметим, что в случае наличия нескольких аргументов с одним и тем же именем этот метод вернет первое из значений, а в случае отсутствия такого аргумента вернет пустую строку.
+
+## Ссылки
+
+- [Содержание](preface.md)
+- Предыдущий раздел: [Пользовательские формы](04.0.md)
+- Следующий раздел: [Проверка введенных данных](04.2.md)
diff --git a/ru/04.2.md b/ru/04.2.md
new file mode 100644
index 00000000..b46ca24f
--- /dev/null
+++ b/ru/04.2.md
@@ -0,0 +1,141 @@
+# 4.2 Verification of inputs
+
+One of the most important principles in web development is that you cannot trust anything from client side user forms. You have to verify all incoming data before use it. Many websites are affected by this problem, which is simple yet crucial.
+
+There are two ways of verify form data that are commonly used. One is JavaScript verification in the front-end, and the other is server verification in the back-end. In this section, we are going to talk about server side verification in web development.
+
+## Required fields
+
+Sometimes we require that users input some fields but they don't, for example in the previous section when we required a username. You can use the `len` function to get the length of a field in order to ensure that users have entered this information.
+
+ if len(r.Form["username"][0])==0{
+ // code for empty field
+ }
+
+`r.Form` treats different form element types differently when they are blank. For empty textboxes, text areas and file uploads, it returns an empty string; for radio buttons and check boxes, it doesn't even create the corresponding items. Instead, you will get errors if you try to access it. Therefore, it's safer to use `r.Form.Get()` to get field values since it will always return empty if the value does not exist. On the other hand, `r.Form.Get()` can only get one field value at a time, so you need to use `r.Form` to get the map of values.
+
+## Numbers
+
+Sometimes you only need numbers for the field value. For example, let's say that you require the age of a user in integer form only, i.e 50 or 10, instead of "old enough" or "young man". If we require a positive number, we can convert the value to the `int` type first, then process it.
+
+ getint,err:=strconv.Atoi(r.Form.Get("age"))
+ if err!=nil{
+ // error occurs when convert to number, it may not a number
+ }
+
+ // check range of number
+ if getint >100 {
+ // too big
+ }
+
+Another way to do this is using regular expressions.
+
+ if m, _ := regexp.MatchString("^[0-9]+$", r.Form.Get("age")); !m {
+ return false
+ }
+
+For high performance purposes, regular expressions are not efficient, however simple regular expressions are usually fast enough. If you are familiar with regular expressions, it's a very convenient way to verify data. Notice that Go uses [RE2](http://code.google.com/p/re2/wiki/Syntax), so all UTF-8 characters are supported.
+
+## Chinese
+
+Sometimes we need users to input their Chinese names and we have to verify that they all use Chinese rather than random characters. For Chinese verification, regular expressions are the only way.
+
+ if m, _ := regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$", r.Form.Get("realname")); !m {
+ return false
+ }
+
+## English letters
+
+Sometimes we need users to input only English letters. For example, we require someone's English name, like astaxie instead of asta谢. We can easily use regular expressions to perform our verification.
+
+ if m, _ := regexp.MatchString("^[a-zA-Z]+$", r.Form.Get("engname")); !m {
+ return false
+ }
+
+## E-mail address
+
+If you want to know whether users have entered valid E-mail addresses, you can use the following regular expression:
+
+ if m, _ := regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`, r.Form.Get("email")); !m {
+ fmt.Println("no")
+ }else{
+ fmt.Println("yes")
+ }
+
+## Drop down list
+
+Let's say we require an item from our drop down list, but instead we get a value fabricated by hackers. How do we prevent this from happening?
+
+Suppose we have the following `